Skip to content

Commit

Permalink
Merge pull request #1381 from gdsfactory/650
Browse files Browse the repository at this point in the history
raise warning with uncached cells
  • Loading branch information
joamatab committed Mar 3, 2023
2 parents a18f327 + 8b3ea0c commit 036661e
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 26 deletions.
55 changes: 29 additions & 26 deletions gdsfactory/component.py
Expand Up @@ -55,6 +55,14 @@
Axis = Literal["x", "y"]


class UncachedComponentWarning(UserWarning):
pass


class UncachedComponentError(ValueError):
pass


class MutabilityError(ValueError):
pass

Expand Down Expand Up @@ -1649,6 +1657,7 @@ def _write_library(
None: do not try to resolve (at your own risk!)
flatten_invalid_refs: flattens component references which have invalid transformations.
max_points: Maximal number of vertices per polygon. Polygons with more vertices that this are automatically fractured.
Oasis settings:
compression_level: Level of compression for cells (between 0 and 9).
Setting to 0 will disable cell compression, 1 gives the best speed and 9, the best compression.
Expand Down Expand Up @@ -1684,6 +1693,18 @@ def _write_library(
write_settings = default_settings.copy(update=explicit_gds_settings)
oasis_settings = default_oasis_settings.copy(update=explicit_oas_settings)

for component in self.get_dependencies(recursive=True):
if not component._locked:
message = (
f"Component {component.name!r} was NOT properly locked. "
"You need to write it into a function that has the @cell decorator."
)
if write_settings.on_uncached_component == "warn":
warnings.warn(message, UncachedComponentWarning)

elif write_settings.on_uncached_component == "error":
raise UncachedComponentError(message)

if write_settings.flatten_invalid_refs:
top_cell = flatten_invalid_refs_recursive(self)
else:
Expand Down Expand Up @@ -1759,57 +1780,45 @@ def write_gds(
self,
gdspath: Optional[PathType] = None,
gdsdir: Optional[PathType] = None,
unit: Optional[float] = None,
precision: Optional[float] = None,
logging: bool = True,
on_duplicate_cell: Optional[str] = None,
flatten_invalid_refs: Optional[bool] = None,
max_points: Optional[int] = None,
**kwargs,
) -> Path:
"""Write component to GDS and returns gdspath.
Args:
gdspath: GDS file path to write to.
gdsdir: directory for the GDS file. Defaults to /tmp/randomFile/gdsfactory.
Keyword Args:
unit: unit size for objects in library. 1um by default.
precision: for dimensions in the library (m). 1nm by default.
logging: disable GDS path logging, for example for showing it in KLayout.
on_duplicate_cell: specify how to resolve duplicate-named cells. Choose one of the following:
"warn" (default): overwrite all duplicate cells with one of the duplicates (arbitrarily).
"error": throw a ValueError when attempting to write a gds with duplicate cells.
"overwrite": overwrite all duplicate cells with one of the duplicates, without warning.
on_uncached_component: Literal["warn", "error"] = "warn"
flatten_invalid_refs: flattens component references which have invalid transformations.
max_points: Maximal number of vertices per polygon.
Polygons with more vertices that this are automatically fractured.
"""

return self._write_library(
gdspath=gdspath,
gdsdir=gdsdir,
unit=unit,
precision=precision,
logging=logging,
on_duplicate_cell=on_duplicate_cell,
flatten_invalid_refs=flatten_invalid_refs,
max_points=max_points,
gdspath=gdspath, gdsdir=gdsdir, with_oasis=False, **kwargs
)

def write_oas(
self,
gdspath: Optional[PathType] = None,
gdsdir: Optional[PathType] = None,
unit: Optional[float] = None,
precision: Optional[float] = None,
logging: bool = True,
on_duplicate_cell: Optional[str] = "warn",
flatten_invalid_refs: Optional[bool] = None,
**kwargs,
) -> Path:
"""Write component to GDS and returns gdspath.
Args:
gdspath: GDS file path to write to.
gdsdir: directory for the GDS file. Defaults to /tmp/randomFile/gdsfactory.
Keyword Args:
unit: unit size for objects in library. 1um by default.
precision: for dimensions in the library (m). 1nm by default.
logging: disable GDS path logging, for example for showing it in KLayout.
Expand All @@ -1818,9 +1827,8 @@ def write_oas(
"error": throw a ValueError when attempting to write a gds with duplicate cells.
"overwrite": overwrite all duplicate cells with one of the duplicates, without warning.
None: do not try to resolve (at your own risk!)
on_uncached_component: Literal["warn", "error"] = "warn"
flatten_invalid_refs: flattens component references which have invalid transformations.
Keyword Args:
compression_level: Level of compression for cells (between 0 and 9).
Setting to 0 will disable cell compression, 1 gives the best speed and 9, the best compression.
detect_rectangles: Store rectangles in compressed format.
Expand All @@ -1833,12 +1841,7 @@ def write_oas(
return self._write_library(
gdspath=gdspath,
gdsdir=gdsdir,
unit=unit,
precision=precision,
logging=logging,
on_duplicate_cell=on_duplicate_cell,
with_oasis=True,
flatten_invalid_refs=flatten_invalid_refs,
**kwargs,
)

Expand Down
11 changes: 11 additions & 0 deletions gdsfactory/config.py
Expand Up @@ -14,6 +14,7 @@

from __future__ import annotations

import warnings
import sys
import io
import json
Expand Down Expand Up @@ -48,6 +49,16 @@
logger.remove()
logger.add(sink=sys.stderr, level="INFO")

showwarning_ = warnings.showwarning


def showwarning(message, *args, **kwargs):
logger.warning(message)
showwarning_(message, *args, **kwargs)


warnings.showwarning = showwarning


def print_version():
"""Print gdsfactory version and install directory."""
Expand Down
2 changes: 2 additions & 0 deletions gdsfactory/pdk.py
Expand Up @@ -5,6 +5,7 @@
import warnings
from functools import partial
from typing import Any, Callable, Optional, Union, Tuple
from typing_extensions import Literal

import numpy as np
from omegaconf import DictConfig
Expand Down Expand Up @@ -51,6 +52,7 @@
class GdsWriteSettings(BaseModel):
"""Settings to use when writing to GDS."""

on_uncached_component: Literal["warn", "error"] = "warn"
unit: float = Field(
default=1e-6,
description="The units of coordinates in the database. The default is 1e-6 (1 micron).",
Expand Down
56 changes: 56 additions & 0 deletions tests/test_uncached_component.py
@@ -0,0 +1,56 @@
from __future__ import annotations

import pytest

import gdsfactory as gf
from gdsfactory.component import UncachedComponentWarning, UncachedComponentError


@gf.cell
def dangerous_intermediate_cells(width=0.5):
"""Example that will show the dangers of using intermediate cells."""
c = gf.Component("safe")
c2 = gf.Component(
"dangerous"
) # This should be forbidden as it will create duplicated cells
c2 << gf.components.hline(width=width)
c << c2
return c


@gf.cell
def using_dangerous_intermediate_cells():
"""Example on how things can go wrong.
Here we try to create to lines with different widths
they end up with two duplicated cells and a name collision on the intermediate cell
"""
c = gf.Component()
c << dangerous_intermediate_cells(width=0.5)
r3 = c << dangerous_intermediate_cells(width=2)
r3.movey(5)
return c


def test_uncached_component_warning():
"""Ensures that an impossible route raises UncachedComponentWarning."""
c = using_dangerous_intermediate_cells()

with pytest.warns(UncachedComponentWarning):
c.write_gds()
return c


def test_uncached_component_error():
"""Ensures that an impossible route raises UncachedComponentError."""
c = using_dangerous_intermediate_cells()

with pytest.raises(UncachedComponentError):
c.write_gds(on_uncached_component="error")
return c


if __name__ == "__main__":
# c = test_uncached_component_warning()
c = test_uncached_component_error()
c.show(show_ports=True)

0 comments on commit 036661e

Please sign in to comment.