Skip to content

Layer

layer

LayerEnum

Bases: int, Enum

Class for having the layers stored and a mapping int <-> layer,datatype.

This Enum can also be treated as a tuple, i.e. it implements __getitem__ and __len__.

Attributes:

Name Type Description
layer int

layer number

datatype int

layer datatype

Source code in kfactory/layer.py
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
class LayerEnum(int, Enum):  # ty:ignore[unsupported-base]
    """Class for having the layers stored and a mapping int <-> layer,datatype.

    This Enum can also be treated as a tuple, i.e. it implements `__getitem__`
    and `__len__`.

    Attributes:
        layer: layer number
        datatype: layer datatype
    """

    layer: int
    datatype: int
    name: str
    layout: constant[kdb.Layout]

    def __init__(self, layer: int, datatype: int) -> None:
        """Just here to make sure klayout knows the layer name."""
        self.layout.set_info(self, kdb.LayerInfo(self.layer, self.datatype, self.name))

    def __new__(
        cls,
        layer: int,
        datatype: int,
    ) -> Self:
        """Create a new Enum.

        Because it needs to act like an integer an enum is created and expanded.

        Args:
            layer: Layer number of the layer.
            datatype: Datatype of the layer.
        """
        value = cls.layout.layer(layer, datatype)
        obj: int = int.__new__(cls, value)
        obj._value_ = value  # ty:ignore[unresolved-attribute]
        obj.layer = layer  # ty:ignore[unresolved-attribute]
        obj.datatype = datatype  # ty:ignore[unresolved-attribute]
        return obj  # ty:ignore[invalid-return-type]

    def __getitem__(self, key: int) -> int:
        """Retrieve layer number[0] / datatype[1] of a layer."""
        if key == 0:
            return self.layer
        if key == 1:
            return self.datatype

        raise ValueError(
            "LayerMap only has two values accessible like"
            " a list, layer == [0] and datatype == [1]"
        )

    def __len__(self) -> int:
        """A layer has length 2, layer number and datatype."""
        return 2

    def __iter__(self) -> Iterator[int]:
        """Allow for loops to iterate over the LayerEnum."""
        yield from [self.layer, self.datatype]

    def __str__(self) -> str:
        """Return the name of the LayerEnum."""
        return self.name

__getitem__

__getitem__(key: int) -> int

Retrieve layer number[0] / datatype[1] of a layer.

Source code in kfactory/layer.py
111
112
113
114
115
116
117
118
119
120
121
def __getitem__(self, key: int) -> int:
    """Retrieve layer number[0] / datatype[1] of a layer."""
    if key == 0:
        return self.layer
    if key == 1:
        return self.datatype

    raise ValueError(
        "LayerMap only has two values accessible like"
        " a list, layer == [0] and datatype == [1]"
    )

__init__

__init__(layer: int, datatype: int) -> None

Just here to make sure klayout knows the layer name.

Source code in kfactory/layer.py
87
88
89
def __init__(self, layer: int, datatype: int) -> None:
    """Just here to make sure klayout knows the layer name."""
    self.layout.set_info(self, kdb.LayerInfo(self.layer, self.datatype, self.name))

__iter__

__iter__() -> Iterator[int]

Allow for loops to iterate over the LayerEnum.

Source code in kfactory/layer.py
127
128
129
def __iter__(self) -> Iterator[int]:
    """Allow for loops to iterate over the LayerEnum."""
    yield from [self.layer, self.datatype]

__len__

__len__() -> int

A layer has length 2, layer number and datatype.

Source code in kfactory/layer.py
123
124
125
def __len__(self) -> int:
    """A layer has length 2, layer number and datatype."""
    return 2

__new__

__new__(layer: int, datatype: int) -> Self

Create a new Enum.

Because it needs to act like an integer an enum is created and expanded.

Parameters:

Name Type Description Default
layer int

Layer number of the layer.

required
datatype int

Datatype of the layer.

required
Source code in kfactory/layer.py
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
def __new__(
    cls,
    layer: int,
    datatype: int,
) -> Self:
    """Create a new Enum.

    Because it needs to act like an integer an enum is created and expanded.

    Args:
        layer: Layer number of the layer.
        datatype: Datatype of the layer.
    """
    value = cls.layout.layer(layer, datatype)
    obj: int = int.__new__(cls, value)
    obj._value_ = value  # ty:ignore[unresolved-attribute]
    obj.layer = layer  # ty:ignore[unresolved-attribute]
    obj.datatype = datatype  # ty:ignore[unresolved-attribute]
    return obj  # ty:ignore[invalid-return-type]

__str__

__str__() -> str

Return the name of the LayerEnum.

Source code in kfactory/layer.py
131
132
133
def __str__(self) -> str:
    """Return the name of the LayerEnum."""
    return self.name

LayerInfos pydantic-model

Bases: BaseModel

Class to store and serialize LayerInfos used in KCLayout.

Parameters:

Name Type Description Default
kwargs Any

kdb.LayerInfo . if any extra field is not a kdb.LayerInfo, the validator will raise a ValidationError.

{}

Config:

  • arbitrary_types_allowed: True
  • extra: allow

Validators:

  • _validate_layers
Source code in kfactory/layer.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
class LayerInfos(BaseModel):
    """Class to store and serialize LayerInfos used in KCLayout.

    Args:
        kwargs: kdb.LayerInfo . if any extra field is not a kdb.LayerInfo,
            the validator will raise a ValidationError.
    """

    model_config = ConfigDict(arbitrary_types_allowed=True, extra="allow")

    def __init__(self, **kwargs: Any) -> None:
        """Initialize the LayerInfos class.

        Args:
            kwargs: kdb.LayerInfo . if any extra field is not a kdb.LayerInfo,
                the validator will raise a ValidationError.
        """
        super().__init__(**kwargs)

    @model_validator(mode="after")
    def _validate_layers(self) -> Self:
        field_names = set(self.__class__.model_fields.keys())
        if self.model_extra is not None:
            field_names |= self.model_extra.keys()
        for field_name in field_names:
            f = getattr(self, field_name)
            if not isinstance(f, kdb.LayerInfo):
                raise InvalidLayerError(
                    "All fields in LayerInfos must be of type kdb.LayerInfo. "
                    f"Field {field_name} is of type {type(f)}"
                )
            if not f.name:
                f.name = field_name
            if f.layer == -1 or f.datatype == -1:
                raise InvalidLayerError(
                    "Layers must specify layer number and datatype."
                    f" {field_name} didn't specify them"
                )
        return self

    def __getitem__(self, value: str) -> kdb.LayerInfo:
        return getattr(self, value)

__init__

__init__(**kwargs: Any) -> None

Initialize the LayerInfos class.

Parameters:

Name Type Description Default
kwargs Any

kdb.LayerInfo . if any extra field is not a kdb.LayerInfo, the validator will raise a ValidationError.

{}
Source code in kfactory/layer.py
37
38
39
40
41
42
43
44
def __init__(self, **kwargs: Any) -> None:
    """Initialize the LayerInfos class.

    Args:
        kwargs: kdb.LayerInfo . if any extra field is not a kdb.LayerInfo,
            the validator will raise a ValidationError.
    """
    super().__init__(**kwargs)

LayerLevel pydantic-model

Bases: BaseModel

Level for 3D LayerStack.

Parameters:

Name Type Description Default
layer tuple[int, int] | LayerInfo

(GDSII Layer number, GDSII datatype).

required
thickness float

layer thickness in um.

required
thickness_tolerance float | None

layer thickness tolerance in um.

None
zmin float

height position where material starts in um.

required
material str | None

material name.

None
sidewall_angle float

in degrees with respect to normal.

0.0
z_to_bias tuple[int, ...] | None

parametrizes shrinking/expansion of the design GDS layer when extruding from zmin (0) to zmin + thickness (1). Defaults no buffering [[0, 1], [0, 0]].

None
info Info | None

simulation_info and other types of metadata. mesh_order: lower mesh order (1) will have priority over higher mesh order (2) in the regions where materials overlap. refractive_index: refractive_index can be int, complex or function that depends on wavelength (um). type: grow, etch, implant, or background. mode: octagon, taper, round. https://gdsfactory.github.io/klayout_pyxs/DocGrow.html into: etch into another layer. https://gdsfactory.github.io/klayout_pyxs/DocGrow.html doping_concentration: for implants. resistivity: for metals. bias: in um for the etch.

None

Fields:

  • layer (tuple[int, int])
  • thickness (float)
  • thickness_tolerance (float | None)
  • zmin (float)
  • material (str | None)
  • sidewall_angle (float)
  • z_to_bias (tuple[int, ...] | None)
  • info (Info)
Source code in kfactory/layer.py
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
class LayerLevel(BaseModel):
    """Level for 3D LayerStack.

    Parameters:
        layer: (GDSII Layer number, GDSII datatype).
        thickness: layer thickness in um.
        thickness_tolerance: layer thickness tolerance in um.
        zmin: height position where material starts in um.
        material: material name.
        sidewall_angle: in degrees with respect to normal.
        z_to_bias: parametrizes shrinking/expansion of the design GDS layer
            when extruding from zmin (0) to zmin + thickness (1).
            Defaults no buffering [[0, 1], [0, 0]].
        info: simulation_info and other types of metadata.
            mesh_order: lower mesh order (1) will have priority over higher
                mesh order (2) in the regions where materials overlap.
            refractive_index: refractive_index
                can be int, complex or function that depends on wavelength (um).
            type: grow, etch, implant, or background.
            mode: octagon, taper, round.
                https://gdsfactory.github.io/klayout_pyxs/DocGrow.html
            into: etch into another layer.
                https://gdsfactory.github.io/klayout_pyxs/DocGrow.html
            doping_concentration: for implants.
            resistivity: for metals.
            bias: in um for the etch.
    """

    layer: tuple[int, int]
    thickness: float
    thickness_tolerance: float | None = None
    zmin: float
    material: str | None = None
    sidewall_angle: float = 0.0
    z_to_bias: tuple[int, ...] | None = None
    info: Info = Info()

    def __init__(
        self,
        layer: tuple[int, int] | kdb.LayerInfo,
        zmin: float,
        thickness: float,
        thickness_tolerance: float | None = None,
        material: str | None = None,
        sidewall_angle: float = 0.0,
        z_to_bias: tuple[int, ...] | None = None,
        info: Info | None = None,
    ) -> None:
        if isinstance(layer, kdb.LayerInfo):
            layer = (layer.layer, layer.datatype)
        super().__init__(
            layer=layer,
            zmin=zmin,
            thickness=thickness,
            thickness_tolerance=thickness_tolerance,
            material=material,
            sidewall_angle=sidewall_angle,
            z_to_bias=z_to_bias,
            info=info or Info(),
        )

LayerStack pydantic-model

Bases: BaseModel

For simulation and 3D rendering.

Parameters:

Name Type Description Default
layers LayerLevel

dict of layer_levels.

{}

Fields:

Source code in kfactory/layer.py
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
class LayerStack(BaseModel):
    """For simulation and 3D rendering.

    Parameters:
        layers: dict of layer_levels.
    """

    layers: dict[str, LayerLevel] = Field(default_factory=dict)

    def __init__(self, **layers: LayerLevel) -> None:
        """Add LayerLevels automatically for subclassed LayerStacks."""
        super().__init__(layers=layers)

    def get_layer_to_thickness(self) -> dict[tuple[int, int], float]:
        """Returns layer tuple to thickness (um)."""
        return {
            level.layer: level.thickness
            for level in self.layers.values()
            if level.thickness
        }

    def get_layer_to_zmin(self) -> dict[tuple[int, int], float]:
        """Returns layer tuple to z min position (um)."""
        return {
            level.layer: level.zmin for level in self.layers.values() if level.thickness
        }

    def get_layer_to_material(self) -> dict[tuple[int, int], str]:
        """Returns layer tuple to material name."""
        return {
            level.layer: level.material
            for level in self.layers.values()
            if level.thickness and level.material
        }

    def get_layer_to_sidewall_angle(self) -> dict[tuple[int, int], float]:
        """Returns layer tuple to material name."""
        return {
            level.layer: level.sidewall_angle
            for level in self.layers.values()
            if level.thickness
        }

    def get_layer_to_info(self) -> dict[tuple[int, int], Info]:
        """Returns layer tuple to info dict."""
        return {level.layer: level.info for level in self.layers.values()}

    def to_dict(self) -> dict[str, dict[str, dict[str, Any]]]:
        return {
            level_name: level.model_dump() for level_name, level in self.layers.items()
        }

    def __getitem__(self, key: str) -> LayerLevel:
        """Access layer stack elements."""
        if key not in self.layers:
            layers = list(self.layers.keys())
            raise KeyError(f"{key!r} not in {layers}")

        return self.layers[key]

    def __getattr__(self, attr: str) -> Any:
        return self.layers[attr]

__getitem__

__getitem__(key: str) -> LayerLevel

Access layer stack elements.

Source code in kfactory/layer.py
250
251
252
253
254
255
256
def __getitem__(self, key: str) -> LayerLevel:
    """Access layer stack elements."""
    if key not in self.layers:
        layers = list(self.layers.keys())
        raise KeyError(f"{key!r} not in {layers}")

    return self.layers[key]

__init__

__init__(**layers: LayerLevel) -> None

Add LayerLevels automatically for subclassed LayerStacks.

Source code in kfactory/layer.py
207
208
209
def __init__(self, **layers: LayerLevel) -> None:
    """Add LayerLevels automatically for subclassed LayerStacks."""
    super().__init__(layers=layers)

get_layer_to_info

get_layer_to_info() -> dict[tuple[int, int], Info]

Returns layer tuple to info dict.

Source code in kfactory/layer.py
241
242
243
def get_layer_to_info(self) -> dict[tuple[int, int], Info]:
    """Returns layer tuple to info dict."""
    return {level.layer: level.info for level in self.layers.values()}

get_layer_to_material

get_layer_to_material() -> dict[tuple[int, int], str]

Returns layer tuple to material name.

Source code in kfactory/layer.py
225
226
227
228
229
230
231
def get_layer_to_material(self) -> dict[tuple[int, int], str]:
    """Returns layer tuple to material name."""
    return {
        level.layer: level.material
        for level in self.layers.values()
        if level.thickness and level.material
    }

get_layer_to_sidewall_angle

get_layer_to_sidewall_angle() -> dict[
    tuple[int, int], float
]

Returns layer tuple to material name.

Source code in kfactory/layer.py
233
234
235
236
237
238
239
def get_layer_to_sidewall_angle(self) -> dict[tuple[int, int], float]:
    """Returns layer tuple to material name."""
    return {
        level.layer: level.sidewall_angle
        for level in self.layers.values()
        if level.thickness
    }

get_layer_to_thickness

get_layer_to_thickness() -> dict[tuple[int, int], float]

Returns layer tuple to thickness (um).

Source code in kfactory/layer.py
211
212
213
214
215
216
217
def get_layer_to_thickness(self) -> dict[tuple[int, int], float]:
    """Returns layer tuple to thickness (um)."""
    return {
        level.layer: level.thickness
        for level in self.layers.values()
        if level.thickness
    }

get_layer_to_zmin

get_layer_to_zmin() -> dict[tuple[int, int], float]

Returns layer tuple to z min position (um).

Source code in kfactory/layer.py
219
220
221
222
223
def get_layer_to_zmin(self) -> dict[tuple[int, int], float]:
    """Returns layer tuple to z min position (um)."""
    return {
        level.layer: level.zmin for level in self.layers.values() if level.thickness
    }