From fda6e495d201f6f2f1bff91fd7f277bfb0ef9e63 Mon Sep 17 00:00:00 2001 From: Sebastian Goeldi Date: Mon, 2 Dec 2024 19:47:38 +0100 Subject: [PATCH] basic klayout pcell implementation --- .pre-commit-config.yaml | 8 ++-- src/kfactory/kcell.py | 96 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dac7cffb..35bc3978 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,7 +21,7 @@ repos: exclude: 'changelog\.d/.*|CHANGELOG\.md' - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.6.9 + rev: v0.8.1 hooks: # Run the linter. - id: ruff @@ -30,7 +30,7 @@ repos: - id: ruff-format exclude: ^tests/ - repo: https://github.com/kynan/nbstripout - rev: 0.7.1 + rev: 0.8.1 hooks: - id: nbstripout files: .ipynb @@ -42,14 +42,14 @@ repos: additional_dependencies: - tomli - repo: https://github.com/PyCQA/bandit - rev: 1.7.10 + rev: 1.8.0 hooks: - id: bandit args: [--exit-zero] # ignore all tests, not just tests data exclude: ^tests/ - repo: https://github.com/pre-commit/mirrors-mypy - rev: 'v1.11.2' # Use the sha / tag you want to point at + rev: 'v1.13.0' # Use the sha / tag you want to point at hooks: - id: mypy require_serial: true diff --git a/src/kfactory/kcell.py b/src/kfactory/kcell.py index 8ed1323b..a9d922d4 100644 --- a/src/kfactory/kcell.py +++ b/src/kfactory/kcell.py @@ -4234,6 +4234,102 @@ def to_dbu( """Convert Shapes or values in dbu to DShapes or floats in um.""" return kdb.CplxTrans(self.layout.dbu).inverted() * other + def pcell( + self, + _func: KCellFunc[KCellParams, None], + ) -> kdb.PCellDeclarationHelper: + """Decorator to cache and auto name the cell. + + This will use `functools.cache` to cache the function call. + Additionally, if enabled this will set the name and from the args/kwargs of the + function and also paste them into a settings dictionary of the + [KCell][kfactory.kcell.KCell]. + + Args: + set_settings: Copy the args & kwargs into the settings dictionary + set_name: Auto create the name of the cell to the functionname plus a + string created from the args/kwargs + check_ports: Check uniqueness of port names. + check_instances: Check for any complex instances. A complex instance is a an + instance that has a magnification != 1 or non-90° rotation. + Depending on the setting, an error is raised, the cell is flattened, + a VInstance is created instead of a regular instance, or they are + ignored. + snap_ports: Snap the centers of the ports onto the grid + (only x/y, not angle). + add_port_layers: Add special layers of + [netlist_layer_mapping][kfactory.kcell.KCLayout.netlist_layer_mapping] + to the ports if the port layer is in the mapping. + cache: Provide a user defined cache instead of an internal one. This + can be used for example to clear the cache. + expensive if the cell is called often). + basename: Overwrite the name normally inferred from the function or class + name. + drop_params: Drop these parameters before writing the + [settings][kfactory.kcell.KCell.settings] + register_factory: Register the resulting KCell-function to the + [factories][kfactory.kcell.KCLayout.factories] + layout_cache: If true, treat the layout like a cache, if a cell with the + same name exists already, pick that one instead of using running the + function. This only works if `set_name` is true. Can be globally + configured through `config.cell_layout_cache`. + overwrite_existing: If cells were created with the same name, delete other + cells with the same name. Can be globally configured through + `config.cell_overwrite_existing`. + info: Additional metadata to put into info attribute. + post_process: List of functions to call after the cell has been created. + debug_names: Check on setting the name whether a cell with this name already + exists. + tags: Tag cell functions with user defined tags. With this, cell functions + can then be retrieved with `kcl.factories.tags[my_tag]` or if filtered + for multiple `kcl.factories.for_tags([my_tag1, my_tag2, ...])`. + """ + sig = inspect.signature(_func) + params: dict[str, KCellParams.kwargs | KCellParams.args] = { + p.name: (p.annotation, p.default) + for k, p in sig.parameters.items() + if p.name != "self" + } + + class KPCell(kdb.PCellDeclarationHelper): + def __init__(self) -> None: + kdb.PCellDeclarationHelper.__init__(self) + for name, (_type, default) in params.items(): + _t = get_origin(_type) + if _t is None: + _t = _type + if _t is float: + t = self.TypeDouble + elif _t is int: + t = self.TypeInt + elif _t is bool: + t = self.TypeBoolean + elif _t is list: + t = self.TypeList + elif _t is str: + t = self.TypeString + elif _t is kdb.Shape: + t = self.TypeShape + elif _t is None: + t = self.TypeNone + else: + raise AttributeError(f"Unsupported type {_type!r}") + self.param( + name, + t, + "", + default=default + if default is not inspect.Parameter.empty + else None, + ) + + def produce_impl(self) -> None: + _func(self, **{name: getattr(self, name) for name in params.keys()}) + + self.register_pcell(_func.__name__, KPCell()) + + return KPCell + @overload def cell( self,