From 224b1155be67526a89be44572e5761914ec59147 Mon Sep 17 00:00:00 2001 From: Lukas Chrostowski Date: Sat, 19 Oct 2024 00:49:52 -0700 Subject: [PATCH 1/6] simply loading PDK libraries --- klayout_dot_config/python/SiEPIC/scripts.py | 167 ++++++++++++++++++ klayout_dot_config/tech/GSiP/__init__.py | 2 +- .../tech/GSiP/pymacros/GSiP_Library.py | 131 -------------- .../tech/GSiP/pymacros/__init__.py | 47 ++++- .../{ => deprecated}/GSiP Library.lym | 3 +- .../GSiP/pymacros/deprecated/GSiP_Library.py | 39 ++++ .../GSiP/pymacros/pcells_GSiP/__init__.py | 6 +- .../pymacros/tests/test_load_libraries.py | 33 ++++ 8 files changed, 290 insertions(+), 138 deletions(-) delete mode 100644 klayout_dot_config/tech/GSiP/pymacros/GSiP_Library.py rename klayout_dot_config/tech/GSiP/pymacros/{ => deprecated}/GSiP Library.lym (98%) create mode 100644 klayout_dot_config/tech/GSiP/pymacros/deprecated/GSiP_Library.py create mode 100644 klayout_dot_config/tech/GSiP/pymacros/tests/test_load_libraries.py diff --git a/klayout_dot_config/python/SiEPIC/scripts.py b/klayout_dot_config/python/SiEPIC/scripts.py index 89c67e386..1699848ef 100644 --- a/klayout_dot_config/python/SiEPIC/scripts.py +++ b/klayout_dot_config/python/SiEPIC/scripts.py @@ -4,6 +4,8 @@ ################################################################################# ''' +Functions in this file: + connect_pins_with_waveguide path_to_waveguide path_to_waveguide2 @@ -34,6 +36,8 @@ zoom_out: When running in the GUI, Zoom out and show full hierarchy export_layout instantiate_all_library_cells +load_klayout_library +technology_libraries ''' @@ -3410,3 +3414,166 @@ def instantiate_all_library_cells(topcell, terminator_cells = None, terminator_l if True or Python_Env == "KLayout_GUI": p.destroy +def load_klayout_library(technology, library_name=None, library_description='', folder_gds=None, folder_pcell=None, verbose=True): + ''' + Load KLayout Library + Loads PCells and fixed cells from sub folders, + creates a KLayout pya.Library, + registers the library with the technology name. + Inputs: + technology: name of the technology, e.g., "EBeam", or pya.Technology + library_name: name of the library + library_description: description of the library + folder_gds: relative sub-folder (within the technology folder) from which to load .gds/.oas fixed cells + folder_pcell: relative sub-folder (within the technology folder) from which to load .py PCells + returns: + pya.Library name + ''' + + if type(technology) == str: + tech = pya.Technology.technology_by_name(technology) + if not tech: + raise Exception('SiEPIC.load_klayout_library cannot load technology: %s' % technology) + tech_name = technology + elif type(technology) == pya.Technology: + tech = technology + if not tech: + raise Exception('SiEPIC.load_klayout_library cannot load technology: %s' % technology) + tech_name = technology.name + else: + raise Exception('SiEPIC.load_klayout_library requires a technology as input.') + + if not library_name: + library_name = tech_name + + import os + import pathlib + import sys + + if verbose: + print(' - Technology path: %s' % tech.default_base_path) + print(' - PCell folder path: %s' % os.path.join(tech.default_base_path, folder_pcell)) + + import importlib.util + import sys + + def import_module_from_path(module_name, file_path): + ''' + import a Python module given a path + ''' + import importlib.util + import sys + from pathlib import Path + + file_path = os.path.join(file_path, '__init__.py') + path = Path(file_path).resolve() + if verbose: + print(' - PCell init file: %s' % path) + spec = importlib.util.spec_from_file_location(module_name, path) + if not spec: + raise Exception('SiEPIC.load_klayout_library cannot import module: %s, from path: %s ' % (module_name,path)) + module = importlib.util.module_from_spec(spec) + sys.modules[module_name] = module # Add it to sys.modules + spec.loader.exec_module(module) # Execute the module code + + return module + + # Load all Python PCells + if folder_pcell: + import importlib + importlib.invalidate_caches() + + # Import the Python folder as a module + folder_pcell_abs = os.path.join(tech.default_base_path, folder_pcell) + module_name = os.path.split(folder_pcell)[-1] + if verbose: + print(' - PCell module name: %s' % module_name) + module = import_module_from_path(module_name, folder_pcell_abs) + globals()[module_name] = module + + # Import all the PCell python files + pcells_=[] + files = [f for f in os.listdir(folder_pcell_abs) if '.py' in pathlib.Path(f).suffixes and '__init__' not in f] + for f in files: + submodule = '%s.%s' % (module_name, f.replace('.py','')) + # m = importlib.import_module(submodule) + m = importlib.import_module('.'+f.replace('.py',''), package=module_name) + if not m: + raise Exception('SiEPIC.load_klayout_library cannot import module: %s, from path: %s ' % (submodule,folder_pcell_abs)) + if verbose: + print(' - imported PCell: %s' % submodule) + pcells_.append(importlib.reload(m)) + if verbose: + print(' - module dir(): %s' % dir(module)) + + if not type(module) == type(os): + raise Exception('SiEPIC.load_klayout_library cannot import module.') + + # Create the KLayout library, using GDS and Python PCells + class library(pya.Library): + def __init__(self): + self.technology=tech_name + if verbose: + print(" - Initializing '%s' Library." % library_name) + + # Set the description + self.description = library_description + + self.register(library_name) + + # Save the path, used for loading WAVEGUIDES.XML + # import os + # self.path = os.path.dirname(os.path.realpath(__file__)) + + # Import all the GDS files from the tech folder + # GDS files + import os, fnmatch + dir_path = os.path.join(tech.default_base_path, folder_gds) + if verbose: + print(' - GDS/OAS folder path: %s' % dir_path) + search_strs = ['*.[Oo][Aa][Ss]', '*.[Gg][Dd][Ss]'] # OAS, GDS + for search_str in search_strs: + for root, dirnames, filenames in os.walk(dir_path, followlinks=True): + for filename in fnmatch.filter(filenames, search_str): + file1=os.path.join(root, filename) + if verbose: + print(" - reading %s" % filename ) + self.layout().read(file1) + + # Create the PCell declarations + for m in pcells_: + mm = m.__name__.replace('%s.' % module_name,'') + # mm2 = m.__name__+'.'+mm+'()' + mm2 = 'module'+'.'+mm+'.'+mm+'()' + if verbose: + print(' - register_pcell %s, %s' % (mm,mm2)) + # self.layout().register_pcell(mm, eval(mm2)) + self.layout().register_pcell(mm, getattr(m,mm)()) + + if verbose: + print(' - done loading pcells') + + # Register us the library with the technology name + # If a library with that name already existed, it will be replaced then. + self.register(library_name) + + library() + + return library_name + +def technology_libraries(tech): + ''' + Function to get a list of all the pya.Library associated with a pya.Technology + missing in KLayout: https://github.com/KLayout/klayout/issues/879 + https://www.klayout.de/doc-qt5/code/class_Technology.html + ''' + import pya + tech_libs = [] + libs = pya.Library.library_ids() + for lib in libs: + l = pya.Library.library_by_id(lib) + if tech in l.technologies(): + tech_libs.append(l.name()) + #print("%s" % (l.name())) + print('Libraries associated with Technology %s: %s' % (tech, tech_libs)) + \ No newline at end of file diff --git a/klayout_dot_config/tech/GSiP/__init__.py b/klayout_dot_config/tech/GSiP/__init__.py index fa595dd81..3b205410d 100644 --- a/klayout_dot_config/tech/GSiP/__init__.py +++ b/klayout_dot_config/tech/GSiP/__init__.py @@ -1,4 +1,4 @@ -print('SiEPIC-GSiP PDK Python module: siepic_gsip_pdk, KLayout technology: GSipP') +print('SiEPIC-GSiP PDK Python module: siepic_gsip_pdk, KLayout technology: GSiP') # Load the KLayout technology, when running in Script mode import pya, os diff --git a/klayout_dot_config/tech/GSiP/pymacros/GSiP_Library.py b/klayout_dot_config/tech/GSiP/pymacros/GSiP_Library.py deleted file mode 100644 index 769343820..000000000 --- a/klayout_dot_config/tech/GSiP/pymacros/GSiP_Library.py +++ /dev/null @@ -1,131 +0,0 @@ -""" -This file is part of the SiEPIC-Tools and SiEPIC-GSiP PDK -by Lukas Chrostowski (c) 2015-2017 - -This Python file implements a library called "GSiP" for scripted and GUI-based layout flows. - -Crash warning: - https://www.klayout.de/forum/comments.php?DiscussionID=734&page=1#Item_13 - This library has nested PCells. Running this macro with a layout open may - cause it to crash. Close the layout first before running. - -Version history: - -Mustafa Hammood 2020/6/25 -- Refactored PCells out of library files into individual files in a subdirectory - -Jaspreet Jhoja 2020/5/23 -- Refactored PCells to make them compatible with both, GUI and script-based layout operations - -Stefan Preble and Karl McNulty (RIT) 2019/6/13 - - Wireguide : Path to metal wires - -Lukas Chrostowski 2017/12/16 - - compatibility with KLayout 0.25 and SiEPIC-Tools - -Lukas Chrostowski - - GDS cells (detector, etc) and PCells (ring modulator, filter) - -todo: -replace: - layout_arc_wg_dbu(self.cell, Layerm1N, x0,y0, r_m1_in, w_m1_in, angle_min_doping, angle_max_doping) -with: - self.cell.shapes(Layerm1N).insert(pya.Polygon(arc(w_m1_in, angle_min_doping, angle_max_doping) + [pya.Point(0, 0)]).transformed(t)) -""" - -folder = 'pcells_GSiP' -verbose = False - -import os, sys, pathlib - -dir_path = os.path.dirname(os.path.realpath(__file__)) -if dir_path not in sys.path: - sys.path.append(dir_path) - -try: - import SiEPIC -except: - dir_path_SiEPIC = os.path.join(dir_path, '../../../python') - sys.path.append(dir_path_SiEPIC) - import SiEPIC - -from SiEPIC._globals import KLAYOUT_VERSION, KLAYOUT_VERSION_3 -if KLAYOUT_VERSION < 28: - question = pya.QMessageBox() - question.setStandardButtons(pya.QMessageBox.Ok) - question.setText("This PDK is not compatible with older versions (<0.28) of KLayout.") - KLayout_link0='https://www.klayout.de/build.html' - question.setInformativeText("\nThis PDK is not compatible with older versions (<0.28) of KLayout.\nPlease download an install the latest version, from %s" % (KLayout_link0)) - pya.QMessageBox_StandardButton(question.exec_()) - -files = [f for f in os.listdir(os.path.join(os.path.dirname( - os.path.realpath(__file__)),folder)) if '.py' in pathlib.Path(f).suffixes and '__init__' not in f] -import importlib -pcells_GSiP = importlib.import_module(folder) -importlib.invalidate_caches() -pcells_=[] -for f in files: - module = '%s.%s' % (folder, f.replace('.py','')) ### folder name ### - if verbose: - print(' - found module: %s' % module) - m = importlib.import_module(module) - if verbose: - print(m) - pcells_.append(importlib.reload(m)) - -import pya - -class GSiP(pya.Library): - def __init__(self): - tech_name = "GSiP" - library = tech_name - self.technology=tech_name - - - if verbose: - print("Initializing '%s' Library." % library) - - # Set the description - self.description = "SiEPIC Generic SiP" - - # Save the path, used for loading WAVEGUIDES.XML - import os - self.path = os.path.dirname(os.path.realpath(__file__)) - - # Import all the GDS files from the tech folder - import os, fnmatch - dir_path = os.path.normpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../gds/building_blocks")) - if verbose: - print(' library path: %s' % dir_path) - search_str = '*.[Oo][Aa][Ss]' # OAS - for root, dirnames, filenames in os.walk(dir_path, followlinks=True): - for filename in fnmatch.filter(filenames, search_str): - file1=os.path.join(root, filename) - if verbose: - print(" - reading %s" % file1 ) - self.layout().read(file1) - search_str = '*.[Gg][Dd][Ss]' # GDS - for root, dirnames, filenames in os.walk(dir_path, followlinks=True): - for filename in fnmatch.filter(filenames, search_str): - file1=os.path.join(root, filename) - if verbose: - print(" - reading %s" % file1 ) - self.layout().read(file1) - - # Create the PCell declarations - for m in pcells_: - mm = m.__name__.replace('%s.' % folder,'') - mm2 = m.__name__+'.'+mm+'()' - if verbose: - print(' - register_pcell %s, %s' % (mm,mm2)) - self.layout().register_pcell(mm, eval(mm2)) - - if verbose: - print(' done with pcells') - - # Register us the library with the technology name - # If a library with that name already existed, it will be replaced then. - self.register(library) - - -GSiP() diff --git a/klayout_dot_config/tech/GSiP/pymacros/__init__.py b/klayout_dot_config/tech/GSiP/pymacros/__init__.py index 0c62ae9ab..83b3191d6 100644 --- a/klayout_dot_config/tech/GSiP/pymacros/__init__.py +++ b/klayout_dot_config/tech/GSiP/pymacros/__init__.py @@ -1,8 +1,51 @@ -print('SiEPIC-GSiP PDK Python module: pymacros') +# $autorun +""" +This file is part of the SiEPIC-Tools and SiEPIC-GSiP PDK +by Lukas Chrostowski (c) 2015-2017 -from . import GSiP_Library +This Python file implements a library called "GSiP" for scripted and GUI-based layout flows. +Crash warning: + https://www.klayout.de/forum/comments.php?DiscussionID=734&page=1#Item_13 + This library has nested PCells. Running this macro with a layout open may + cause it to crash. Close the layout first before running. +Version history: +Mustafa Hammood 2020/6/25 +- Refactored PCells out of library files into individual files in a subdirectory +Jaspreet Jhoja 2020/5/23 +- Refactored PCells to make them compatible with both, GUI and script-based layout operations + +Stefan Preble and Karl McNulty (RIT) 2019/6/13 + - Wireguide : Path to metal wires + +Lukas Chrostowski 2017/12/16 + - compatibility with KLayout 0.25 and SiEPIC-Tools + +Lukas Chrostowski + - GDS cells (detector, etc) and PCells (ring modulator, filter) + +Lukas 2023/11 + - compatibility with PyPI usage of KLayout + +Lukas 2024/10 + - moving all the library loading code into SiEPIC.scripts.load_klayout_library + +""" + +print('SiEPIC-GSiP PDK Python module: load library GDS/OAS cells and PCells') + +verbose = False + +tech = 'GSiP' + +from SiEPIC.scripts import load_klayout_library , technology_libraries + +# Load the library +load_klayout_library(tech, tech, 'SiEPIC Generic SiP, v1.1', 'gds/building_blocks','pymacros/pcells_GSiP', verbose=verbose) + +# List the libraries loaded +technology_libraries(tech) diff --git a/klayout_dot_config/tech/GSiP/pymacros/GSiP Library.lym b/klayout_dot_config/tech/GSiP/pymacros/deprecated/GSiP Library.lym similarity index 98% rename from klayout_dot_config/tech/GSiP/pymacros/GSiP Library.lym rename to klayout_dot_config/tech/GSiP/pymacros/deprecated/GSiP Library.lym index f71cd429b..c31ccb46c 100644 --- a/klayout_dot_config/tech/GSiP/pymacros/GSiP Library.lym +++ b/klayout_dot_config/tech/GSiP/pymacros/deprecated/GSiP Library.lym @@ -6,8 +6,9 @@ - true + false false + 0 false diff --git a/klayout_dot_config/tech/GSiP/pymacros/deprecated/GSiP_Library.py b/klayout_dot_config/tech/GSiP/pymacros/deprecated/GSiP_Library.py new file mode 100644 index 000000000..f79687b0a --- /dev/null +++ b/klayout_dot_config/tech/GSiP/pymacros/deprecated/GSiP_Library.py @@ -0,0 +1,39 @@ +""" +This file is part of the SiEPIC-Tools and SiEPIC-GSiP PDK +by Lukas Chrostowski (c) 2015-2017 + +This Python file implements a library called "GSiP" for scripted and GUI-based layout flows. + +Crash warning: + https://www.klayout.de/forum/comments.php?DiscussionID=734&page=1#Item_13 + This library has nested PCells. Running this macro with a layout open may + cause it to crash. Close the layout first before running. + +Version history: + +Mustafa Hammood 2020/6/25 +- Refactored PCells out of library files into individual files in a subdirectory + +Jaspreet Jhoja 2020/5/23 +- Refactored PCells to make them compatible with both, GUI and script-based layout operations + +Stefan Preble and Karl McNulty (RIT) 2019/6/13 + - Wireguide : Path to metal wires + +Lukas Chrostowski 2017/12/16 + - compatibility with KLayout 0.25 and SiEPIC-Tools + +Lukas Chrostowski + - GDS cells (detector, etc) and PCells (ring modulator, filter) + +Lukas 2023/11 + - compatibility with PyPI usage of KLayout + +Lukas 2024/10 + - moving all the library loading code into SiEPIC.scripts.load_klayout_library + +""" + +from SiEPIC.scripts import load_klayout_library + +load_klayout_library('GSiP', 'GSiP', 'SiEPIC Generic SiP, v1.1', 'gds/building_blocks','pymacros/pcells_GSiP', verbose=False) diff --git a/klayout_dot_config/tech/GSiP/pymacros/pcells_GSiP/__init__.py b/klayout_dot_config/tech/GSiP/pymacros/pcells_GSiP/__init__.py index bc72996d9..8b563f7d8 100644 --- a/klayout_dot_config/tech/GSiP/pymacros/pcells_GSiP/__init__.py +++ b/klayout_dot_config/tech/GSiP/pymacros/pcells_GSiP/__init__.py @@ -1,4 +1,4 @@ -import os, sys -import SiEPIC +# import os, sys +# import SiEPIC -from SiEPIC.utils import get_technology_by_name +# from SiEPIC.utils import get_technology_by_name diff --git a/klayout_dot_config/tech/GSiP/pymacros/tests/test_load_libraries.py b/klayout_dot_config/tech/GSiP/pymacros/tests/test_load_libraries.py new file mode 100644 index 000000000..e48b914f4 --- /dev/null +++ b/klayout_dot_config/tech/GSiP/pymacros/tests/test_load_libraries.py @@ -0,0 +1,33 @@ + +if 0: + import os + print(os.path.split('pymacros/pcells_GSiP')[-1]) + +if 1: + import os + import SiEPIC + # Load the PDK from a folder, e.g, GitHub, when running externally from the KLayout Application + import sys + p = os.path.abspath(os.path.join(SiEPIC.__path__[0], '../..', 'tech')) + sys.path.insert(0,p) + #print (p) + #print(sys.path) + import GSiP + + + +if 0: + import importlib.util + import sys + from pathlib import Path + path = '/Users/lukasc/Documents/GitHub/SiEPIC-Tools/klayout_dot_config/tech/GSiP/pymacros/pcells_GSiP/__init__.py' + module_name = 'pcells_GSiP' + path = Path(path).resolve() + spec = importlib.util.spec_from_file_location(module_name, path) + module = importlib.util.module_from_spec(spec) + sys.modules[module_name] = module # Add it to sys.modules + spec.loader.exec_module(module) # Execute the module code + print(dir(module)) + module.Ring_Filter_DB + + From 76b5122324298a947eab3996579ed7f65daf647e Mon Sep 17 00:00:00 2001 From: Lukas Chrostowski Date: Sat, 19 Oct 2024 00:57:28 -0700 Subject: [PATCH 2/6] Update test_load_libraries.py --- .../GSiP/pymacros/{tests => deprecated}/test_load_libraries.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename klayout_dot_config/tech/GSiP/pymacros/{tests => deprecated}/test_load_libraries.py (100%) diff --git a/klayout_dot_config/tech/GSiP/pymacros/tests/test_load_libraries.py b/klayout_dot_config/tech/GSiP/pymacros/deprecated/test_load_libraries.py similarity index 100% rename from klayout_dot_config/tech/GSiP/pymacros/tests/test_load_libraries.py rename to klayout_dot_config/tech/GSiP/pymacros/deprecated/test_load_libraries.py From 39c8fbefb5a698d20d1c08f29ddcb9b3d18848a7 Mon Sep 17 00:00:00 2001 From: Lukas Chrostowski Date: Sat, 19 Oct 2024 01:08:27 -0700 Subject: [PATCH 3/6] Create python-publish.yml --- .github/workflows/python-publish.yml | 43 ++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .github/workflows/python-publish.yml diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml new file mode 100644 index 000000000..be9f6b8be --- /dev/null +++ b/.github/workflows/python-publish.yml @@ -0,0 +1,43 @@ +# This workflow will upload a Python Package using Twine when a release is created +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Upload Python Package + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + deploy: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install build + - name: Build package + run: | + # python -m build + cd klayout_dot_config/python + python3 -m build + cp -a dist ../.. + - name: Publish package + uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} From d02200c190dbe3f15361e77880bc1065bfb32a86 Mon Sep 17 00:00:00 2001 From: Lukas Chrostowski Date: Sat, 19 Oct 2024 01:28:47 -0700 Subject: [PATCH 4/6] update scripts.load_klayout_library --- klayout_dot_config/python/SiEPIC/scripts.py | 53 +++++++++++---------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/klayout_dot_config/python/SiEPIC/scripts.py b/klayout_dot_config/python/SiEPIC/scripts.py index 1699848ef..9af1a8f7c 100644 --- a/klayout_dot_config/python/SiEPIC/scripts.py +++ b/klayout_dot_config/python/SiEPIC/scripts.py @@ -3506,8 +3506,8 @@ def import_module_from_path(module_name, file_path): if verbose: print(' - module dir(): %s' % dir(module)) - if not type(module) == type(os): - raise Exception('SiEPIC.load_klayout_library cannot import module.') + if not type(module) == type(os): + raise Exception('SiEPIC.load_klayout_library cannot import module.') # Create the KLayout library, using GDS and Python PCells class library(pya.Library): @@ -3525,33 +3525,34 @@ def __init__(self): # import os # self.path = os.path.dirname(os.path.realpath(__file__)) - # Import all the GDS files from the tech folder - # GDS files - import os, fnmatch - dir_path = os.path.join(tech.default_base_path, folder_gds) - if verbose: - print(' - GDS/OAS folder path: %s' % dir_path) - search_strs = ['*.[Oo][Aa][Ss]', '*.[Gg][Dd][Ss]'] # OAS, GDS - for search_str in search_strs: - for root, dirnames, filenames in os.walk(dir_path, followlinks=True): - for filename in fnmatch.filter(filenames, search_str): - file1=os.path.join(root, filename) - if verbose: - print(" - reading %s" % filename ) - self.layout().read(file1) + # Import all the GDS/OASIS files from the tech folder + if folder_gds: + import os, fnmatch + dir_path = os.path.join(tech.default_base_path, folder_gds) + if verbose: + print(' - GDS/OAS folder path: %s' % dir_path) + search_strs = ['*.[Oo][Aa][Ss]', '*.[Gg][Dd][Ss]'] # OAS, GDS + for search_str in search_strs: + for root, dirnames, filenames in os.walk(dir_path, followlinks=True): + for filename in fnmatch.filter(filenames, search_str): + file1=os.path.join(root, filename) + if verbose: + print(" - reading %s" % filename ) + self.layout().read(file1) # Create the PCell declarations - for m in pcells_: - mm = m.__name__.replace('%s.' % module_name,'') - # mm2 = m.__name__+'.'+mm+'()' - mm2 = 'module'+'.'+mm+'.'+mm+'()' + if folder_pcell: + for m in pcells_: + mm = m.__name__.replace('%s.' % module_name,'') + # mm2 = m.__name__+'.'+mm+'()' + mm2 = 'module'+'.'+mm+'.'+mm+'()' + if verbose: + print(' - register_pcell %s, %s' % (mm,mm2)) + # self.layout().register_pcell(mm, eval(mm2)) + self.layout().register_pcell(mm, getattr(m,mm)()) + if verbose: - print(' - register_pcell %s, %s' % (mm,mm2)) - # self.layout().register_pcell(mm, eval(mm2)) - self.layout().register_pcell(mm, getattr(m,mm)()) - - if verbose: - print(' - done loading pcells') + print(' - done loading pcells') # Register us the library with the technology name # If a library with that name already existed, it will be replaced then. From 2fbbc7525edd46db175e0b12dba2d3349e9218f7 Mon Sep 17 00:00:00 2001 From: Lukas Chrostowski Date: Sat, 19 Oct 2024 01:34:22 -0700 Subject: [PATCH 5/6] Update run-layout-tests.yml --- .github/workflows/run-layout-tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run-layout-tests.yml b/.github/workflows/run-layout-tests.yml index 5a63ee84e..eaede9f47 100644 --- a/.github/workflows/run-layout-tests.yml +++ b/.github/workflows/run-layout-tests.yml @@ -31,8 +31,9 @@ jobs: - name: install python 3.11 packages run: | - python -m pip install --upgrade pip + # python -m pip install --upgrade pip pip install klayout numpy scipy pytest pytest-cov IPython + pip install -e klayout_dot_config/python - name: Test with pytest, python 3.11 run: pytest --cov=klayout_dot_config/python/SiEPIC klayout_dot_config/tech --cov-report=xml From b7c4e4253f6fd5907e3f03e1ae3b93102f1c9c8e Mon Sep 17 00:00:00 2001 From: Lukas Chrostowski Date: Sat, 19 Oct 2024 02:00:45 -0700 Subject: [PATCH 6/6] v0.5.14 --- klayout_dot_config/grain.xml | 2 +- klayout_dot_config/python/SiEPIC/__init__.py | 2 +- klayout_dot_config/python/SiEPIC/scripts.py | 36 ++++++++++++++++---- klayout_dot_config/python/pyproject.toml | 2 +- 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/klayout_dot_config/grain.xml b/klayout_dot_config/grain.xml index ab392283f..91e98050a 100644 --- a/klayout_dot_config/grain.xml +++ b/klayout_dot_config/grain.xml @@ -1,7 +1,7 @@ siepic_tools - 0.5.13 + 0.5.14 0.27 SiEPIC Tools Tools for designing Silicon Photonic Integrated Circuits, including waveguides, component simulations, functional verification, DRC verification, Functional verification, netlist extraction, circuit simulations. Layout can be implemented graphically or by programming in Python using the SiEPIC functions and KLayout Python API. Framework and examples for creating layouts using scripts. Includes a generic PDK (GSiP). Other PDKs are installed separately, and depend on SiEPIC-Tools. diff --git a/klayout_dot_config/python/SiEPIC/__init__.py b/klayout_dot_config/python/SiEPIC/__init__.py index fafc5d8d9..25d94ff76 100644 --- a/klayout_dot_config/python/SiEPIC/__init__.py +++ b/klayout_dot_config/python/SiEPIC/__init__.py @@ -2,7 +2,7 @@ SiEPIC-Tools package for KLayout ''' -__version__ = "0.5.13" +__version__ = "0.5.14" print("KLayout SiEPIC-Tools version %s" %__version__) diff --git a/klayout_dot_config/python/SiEPIC/scripts.py b/klayout_dot_config/python/SiEPIC/scripts.py index 9af1a8f7c..0026d94f9 100644 --- a/klayout_dot_config/python/SiEPIC/scripts.py +++ b/klayout_dot_config/python/SiEPIC/scripts.py @@ -3484,7 +3484,7 @@ def import_module_from_path(module_name, file_path): importlib.invalidate_caches() # Import the Python folder as a module - folder_pcell_abs = os.path.join(tech.default_base_path, folder_pcell) + folder_pcell_abs = os.path.abspath(os.path.join(tech.default_base_path, folder_pcell)) module_name = os.path.split(folder_pcell)[-1] if verbose: print(' - PCell module name: %s' % module_name) @@ -3528,10 +3528,11 @@ def __init__(self): # Import all the GDS/OASIS files from the tech folder if folder_gds: import os, fnmatch - dir_path = os.path.join(tech.default_base_path, folder_gds) + dir_path = os.path.abspath(os.path.join(tech.default_base_path, folder_gds)) if verbose: print(' - GDS/OAS folder path: %s' % dir_path) search_strs = ['*.[Oo][Aa][Ss]', '*.[Gg][Dd][Ss]'] # OAS, GDS + found = False for search_str in search_strs: for root, dirnames, filenames in os.walk(dir_path, followlinks=True): for filename in fnmatch.filter(filenames, search_str): @@ -3539,9 +3540,15 @@ def __init__(self): if verbose: print(" - reading %s" % filename ) self.layout().read(file1) + found = True + if not found: + print(' - Warning: no fixed GDS/OAS files found for library: %s, in folder: %s' % (library_name, dir_path)) + # Create the PCell declarations if folder_pcell: + if not pcells_: + print(' - Warning: no PCells found for library: %s' % library_name) for m in pcells_: mm = m.__name__.replace('%s.' % module_name,'') # mm2 = m.__name__+'.'+mm+'()' @@ -3562,19 +3569,34 @@ def __init__(self): return library_name -def technology_libraries(tech): +def technology_libraries(technology): ''' Function to get a list of all the pya.Library associated with a pya.Technology missing in KLayout: https://github.com/KLayout/klayout/issues/879 https://www.klayout.de/doc-qt5/code/class_Technology.html + Inputs: + technology: name of the technology, e.g., "EBeam", or pya.Technology ''' - import pya + + if type(technology) == str: + tech = pya.Technology.technology_by_name(technology) + if not tech: + raise Exception('SiEPIC.load_klayout_library cannot load technology: %s' % technology) + tech_name = technology + elif type(technology) == pya.Technology: + tech = technology + if not tech: + raise Exception('SiEPIC.load_klayout_library cannot load technology: %s' % technology) + tech_name = technology.name + else: + raise Exception('SiEPIC.load_klayout_library requires a technology as input.') + tech_libs = [] libs = pya.Library.library_ids() for lib in libs: l = pya.Library.library_by_id(lib) - if tech in l.technologies(): + if tech_name in l.technologies(): tech_libs.append(l.name()) - #print("%s" % (l.name())) - print('Libraries associated with Technology %s: %s' % (tech, tech_libs)) + + print('Libraries associated with Technology %s: %s' % (tech_name, tech_libs)) \ No newline at end of file diff --git a/klayout_dot_config/python/pyproject.toml b/klayout_dot_config/python/pyproject.toml index 83edee332..43473d0f2 100644 --- a/klayout_dot_config/python/pyproject.toml +++ b/klayout_dot_config/python/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "SiEPIC" -version = "0.5.13" +version = "0.5.14" authors = [ { name="Lukas Chrostowski", email="lukasc@ece.ubc.ca" }, ]