Read - Docs

Skip to content

# Read

Provides functions to create Devices from various data sources.

## `from_gds(gds_path, cell_name, gds_layer=(1, 0), bounds=None, **kwargs)`

Create a Device from a GDS cell.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`gds_path` | `str` | The file path to the GDS file. | required
`cell_name` | `str` | The name of the cell within the GDS file to be converted into a Device object. | required
`gds_layer` | `tuple[int, int]` | A tuple specifying the layer and datatype to be used from the GDS file. Defaults to (1, 0). | `(1, 0)`
`bounds` | `tuple[tuple[int, int], tuple[int, int]]` | A tuple specifying the bounds for cropping the cell before conversion, formatted as ((min_x, min_y), (max_x, max_y)), in units of the GDS file. If None, the entire cell is used. | `None`
`**kwargs` |  | Additional keyword arguments to be passed to the Device constructor. | `{}`

Returns:

Type | Description
--- | ---
`Device` | A Device object representing the specified cell from the GDS file, after processing based on the specified layer.

Source code in `prefab/read.py`

     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
    def from_gds(
        gds_path: str,
        cell_name: str,
        gds_layer: tuple[int, int] = (1, 0),
        bounds: tuple[tuple[int, int], tuple[int, int]] = None,
        **kwargs,
    ):
        """
        Create a Device from a GDS cell.

        Parameters
        ----------
        gds_path : str
            The file path to the GDS file.
        cell_name : str
            The name of the cell within the GDS file to be converted into a Device object.
        gds_layer : tuple[int, int], optional
            A tuple specifying the layer and datatype to be used from the GDS file. Defaults
            to (1, 0).
        bounds : tuple[tuple[int, int], tuple[int, int]], optional
            A tuple specifying the bounds for cropping the cell before conversion, formatted
            as ((min_x, min_y), (max_x, max_y)), in units of the GDS file. If None, the
            entire cell is used.
        **kwargs
            Additional keyword arguments to be passed to the Device constructor.

        Returns
        -------
        Device
            A Device object representing the specified cell from the GDS file, after
            processing based on the specified layer.
        """
        gdstk_library = gdstk.read_gds(gds_path)
        gdstk_cell = gdstk_library[cell_name]
        device_array = _gdstk_to_device_array(
            gdstk_cell=gdstk_cell, gds_layer=gds_layer, bounds=bounds
        )
        return Device(device_array=device_array, **kwargs)

## `from_gdstk(gdstk_cell, gds_layer=(1, 0), bounds=None, **kwargs)`

Create a Device from a gdstk cell.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`gdstk_cell` | `Cell` | The gdstk.Cell object to be converted into a Device object. | required
`gds_layer` | `tuple[int, int]` | A tuple specifying the layer and datatype to be used. Defaults to (1, 0). | `(1, 0)`
`bounds` | `tuple[tuple[int, int], tuple[int, int]]` | A tuple specifying the bounds for cropping the cell before conversion, formatted as ((min_x, min_y), (max_x, max_y)), in units of the GDS file. If None, the entire cell is used. | `None`
`**kwargs` |  | Additional keyword arguments to be passed to the Device constructor. | `{}`

Returns:

Type | Description
--- | ---
`Device` | A Device object representing the gdstk.Cell, after processing based on the specified layer.

Source code in `prefab/read.py`

    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    def from_gdstk(
        gdstk_cell: gdstk.Cell,
        gds_layer: tuple[int, int] = (1, 0),
        bounds: tuple[tuple[int, int], tuple[int, int]] = None,
        **kwargs,
    ):
        """
        Create a Device from a gdstk cell.

        Parameters
        ----------
        gdstk_cell : gdstk.Cell
            The gdstk.Cell object to be converted into a Device object.
        gds_layer : tuple[int, int], optional
            A tuple specifying the layer and datatype to be used. Defaults to (1, 0).
        bounds : tuple[tuple[int, int], tuple[int, int]], optional
            A tuple specifying the bounds for cropping the cell before conversion, formatted
            as ((min_x, min_y), (max_x, max_y)), in units of the GDS file. If None, the
            entire cell is used.
        **kwargs
            Additional keyword arguments to be passed to the Device constructor.

        Returns
        -------
        Device
            A Device object representing the gdstk.Cell, after processing based on the
            specified layer.
        """
        device_array = _gdstk_to_device_array(
            gdstk_cell=gdstk_cell, gds_layer=gds_layer, bounds=bounds
        )
        return Device(device_array=device_array, **kwargs)

## `from_img(img_path, img_width_nm=None, binarize=True, **kwargs)`

Create a Device from an image file.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`img_path` | `str` | The path to the image file to be converted into a Device object. | required
`img_width_nm` | `int` | The desired width of the device in nanometers. If specified, the image will be resized to this width while maintaining aspect ratio. If None, no resizing is performed. | `None`
`binarize` | `bool` | If True, the image will be binarized (converted to binary values) before conversion to a Device object. This is useful for converting grayscale images into binary masks. Defaults to True. | `True`
`**kwargs` |  | Additional keyword arguments to be passed to the Device constructor. | `{}`

Returns:

Type | Description
--- | ---
`Device` | A Device object representing the processed image, after optional resizing and binarization.

Source code in `prefab/read.py`

    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    def from_img(
        img_path: str, img_width_nm: int = None, binarize: bool = True, **kwargs
    ) -> Device:
        """
        Create a Device from an image file.

        Parameters
        ----------
        img_path : str
            The path to the image file to be converted into a Device object.
        img_width_nm : int, optional
            The desired width of the device in nanometers. If specified, the image will be
            resized to this width while maintaining aspect ratio. If None, no resizing is
            performed.
        binarize : bool, optional
            If True, the image will be binarized (converted to binary values) before
            conversion to a Device object. This is useful for converting grayscale images
            into binary masks. Defaults to True.
        **kwargs
            Additional keyword arguments to be passed to the Device constructor.

        Returns
        -------
        Device
            A Device object representing the processed image, after optional resizing and
            binarization.
        """
        device_array = cv2.imread(img_path, flags=cv2.IMREAD_GRAYSCALE) / 255
        if img_width_nm is not None:
            scale = img_width_nm / device_array.shape[1]
            device_array = cv2.resize(device_array, dsize=(0, 0), fx=scale, fy=scale)
        if binarize:
            device_array = geometry.binarize_hard(device_array)
        return Device(device_array=device_array, **kwargs)

## `from_ndarray(ndarray, resolution=1, binarize=True, **kwargs)`

Create a Device from an ndarray.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`ndarray` | `ndarray` | The input array representing the device layout. | required
`resolution` | `int` | The resolution of the ndarray in nanometers per pixel, defaulting to 1 nm per pixel. If specified, the input array will be resized based on this resolution to match the desired physical size. | `1`
`binarize` | `bool` | If True, the input array will be binarized (converted to binary values) before conversion to a Device object. This is useful for processing grayscale images into binary masks. Defaults to True. | `True`
`**kwargs` |  | Additional keyword arguments to be passed to the Device constructor. | `{}`

Returns:

Type | Description
--- | ---
`Device` | A Device object representing the input array, after optional resizing and binarization.

Source code in `prefab/read.py`

    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    def from_ndarray(
        ndarray: np.ndarray, resolution: int = 1, binarize: bool = True, **kwargs
    ) -> Device:
        """
        Create a Device from an ndarray.

        Parameters
        ----------
        ndarray : np.ndarray
            The input array representing the device layout.
        resolution : int, optional
            The resolution of the ndarray in nanometers per pixel, defaulting to 1 nm per
            pixel. If specified, the input array will be resized based on this resolution to
            match the desired physical size.
        binarize : bool, optional
            If True, the input array will be binarized (converted to binary values) before
            conversion to a Device object. This is useful for processing grayscale images
            into binary masks. Defaults to True.
        **kwargs
            Additional keyword arguments to be passed to the Device constructor.

        Returns
        -------
        Device
            A Device object representing the input array, after optional resizing and
            binarization.
        """
        device_array = ndarray
        device_array = cv2.resize(device_array, dsize=(0, 0), fx=resolution, fy=resolution)
        if binarize:
            device_array = geometry.binarize_hard(device_array)
        return Device(device_array=device_array, **kwargs)

## `from_sem(sem_path, sem_resolution=None, sem_resolution_key=None, binarize=True, bounds=None, **kwargs)`

Create a Device from a scanning electron microscope (SEM) image file.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`sem_path` | `str` | The file path to the SEM image. | required
`sem_resolution` | `float` | The resolution of the SEM image in nanometers per pixel. If not provided, it will be extracted from the image metadata using the `sem_resolution_key`. | `None`
`sem_resolution_key` | `str` | The key to look for in the SEM image metadata to extract the resolution. Required if `sem_resolution` is not provided. | `None`
`binarize` | `bool` | If True, the SEM image will be binarized (converted to binary values) before conversion to a Device object. This is needed for processing grayscale images into binary masks. Defaults to True. | `True`
`bounds` | `tuple[tuple[int, int], tuple[int, int]]` | A tuple specifying the bounds for cropping the image before conversion, formatted as ((min_x, min_y), (max_x, max_y)). If None, the entire image is used. | `None`
`**kwargs` |  | Additional keyword arguments to be passed to the Device constructor. | `{}`

Returns:

Type | Description
--- | ---
`Device` | A Device object representing the processed SEM image.

Raises:

Type | Description
--- | ---
`ValueError` | If neither `sem_resolution` nor `sem_resolution_key` is provided.

Source code in `prefab/read.py`

    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
    def from_sem(
        sem_path: str,
        sem_resolution: float = None,
        sem_resolution_key: str = None,
        binarize: bool = True,
        bounds: tuple[tuple[int, int], tuple[int, int]] = None,
        **kwargs,
    ) -> Device:
        """
        Create a Device from a scanning electron microscope (SEM) image file.

        Parameters
        ----------
        sem_path : str
            The file path to the SEM image.
        sem_resolution : float, optional
            The resolution of the SEM image in nanometers per pixel. If not provided, it
            will be extracted from the image metadata using the `sem_resolution_key`.
        sem_resolution_key : str, optional
            The key to look for in the SEM image metadata to extract the resolution.
            Required if `sem_resolution` is not provided.
        binarize : bool, optional
            If True, the SEM image will be binarized (converted to binary values) before
            conversion to a Device object. This is needed for processing grayscale images
            into binary masks. Defaults to True.
        bounds : tuple[tuple[int, int], tuple[int, int]], optional
            A tuple specifying the bounds for cropping the image before conversion,
            formatted as ((min_x, min_y), (max_x, max_y)). If None, the entire image is
            used.
        **kwargs
            Additional keyword arguments to be passed to the Device constructor.

        Returns
        -------
        Device
            A Device object representing the processed SEM image.

        Raises
        ------
        ValueError
            If neither `sem_resolution` nor `sem_resolution_key` is provided.
        """
        if sem_resolution is None and sem_resolution_key is not None:
            sem_resolution = get_sem_resolution(sem_path, sem_resolution_key)
        elif sem_resolution is None:
            raise ValueError("Either sem_resolution or resolution_key must be provided.")

        device_array = cv2.imread(sem_path, flags=cv2.IMREAD_GRAYSCALE)
        if sem_resolution is not None:
            device_array = cv2.resize(
                device_array, dsize=(0, 0), fx=sem_resolution, fy=sem_resolution
            )
        if bounds is not None:
            device_array = device_array[
                -bounds[1][1] : -bounds[0][1], bounds[0][0] : bounds[1][0]
            ]
        if binarize:
            device_array = geometry.binarize_sem(device_array)
        return Device(device_array=device_array, **kwargs)

## `get_sem_resolution(sem_path, sem_resolution_key)`

Extracts the resolution of a scanning electron microscope (SEM) image from its metadata.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`sem_path` | `str` | The file path to the SEM image. | required
`sem_resolution_key` | `str` | The key to look for in the SEM image metadata to extract the resolution. | required

Returns:

Type | Description
--- | ---
`float` | The resolution of the SEM image in nanometers per pixel.

Raises:

Type | Description
--- | ---
`ValueError` | If the resolution key is not found in the SEM image metadata.

Source code in `prefab/read.py`

    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    def get_sem_resolution(sem_path: str, sem_resolution_key: str) -> float:
        """
        Extracts the resolution of a scanning electron microscope (SEM) image from its
        metadata.

        Parameters
        ----------
        sem_path : str
            The file path to the SEM image.
        sem_resolution_key : str
            The key to look for in the SEM image metadata to extract the resolution.

        Returns
        -------
        float
            The resolution of the SEM image in nanometers per pixel.

        Raises
        ------
        ValueError
            If the resolution key is not found in the SEM image metadata.
        """
        with open(sem_path, "rb") as file:
            resolution_key_bytes = sem_resolution_key.encode("utf-8")
            for line in file:
                if resolution_key_bytes in line:
                    line_str = line.decode("utf-8")
                    match = re.search(r"-?\d+(\.\d+)?", line_str)
                    if match:
                        value = float(match.group())
                        if value > 100:
                            value /= 1000
                        return value
        raise ValueError(f"Resolution key '{sem_resolution_key}' not found in {sem_path}.")