[file.gdsii] rework gdsii module hierarchy
This commit is contained in:
parent
02a3708b30
commit
088c37e9d2
14 changed files with 72 additions and 59 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
from masque.file.gdsii_perf import main
|
from masque.file.gdsii.perf import main
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ from masque import LibraryError
|
||||||
|
|
||||||
READERS: dict[str, tuple[str, tuple[str, ...]]] = {
|
READERS: dict[str, tuple[str, tuple[str, ...]]] = {
|
||||||
'gdsii': ('masque.file.gdsii', ('readfile',)),
|
'gdsii': ('masque.file.gdsii', ('readfile',)),
|
||||||
'gdsii_arrow': ('masque.file.gdsii_arrow', ('readfile', 'arrow_import', 'arrow_convert')),
|
'gdsii_arrow': ('masque.file.gdsii.arrow', ('readfile', 'arrow_import', 'arrow_convert')),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ from pprint import pformat
|
||||||
|
|
||||||
from masque import BuildLibrary, Pather, Pattern, cell
|
from masque import BuildLibrary, Pather, Pattern, cell
|
||||||
from masque.file.gdsii import writefile
|
from masque.file.gdsii import writefile
|
||||||
from masque.file.gdsii_lazy import readfile
|
from masque.file.gdsii.lazy import readfile
|
||||||
|
|
||||||
import basic_shapes
|
import basic_shapes
|
||||||
import devices
|
import devices
|
||||||
|
|
|
||||||
10
masque/file/gdsii/__init__.py
Normal file
10
masque/file/gdsii/__init__.py
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
"""
|
||||||
|
GDSII file format readers and writers.
|
||||||
|
"""
|
||||||
|
from .klamath import check_valid_names as check_valid_names
|
||||||
|
from .klamath import read as read
|
||||||
|
from .klamath import read_elements as read_elements
|
||||||
|
from .klamath import readfile as readfile
|
||||||
|
from .klamath import rint_cast as rint_cast
|
||||||
|
from .klamath import write as write
|
||||||
|
from .klamath import writefile as writefile
|
||||||
|
|
@ -43,12 +43,12 @@ from numpy.typing import ArrayLike, NDArray
|
||||||
import pyarrow
|
import pyarrow
|
||||||
from pyarrow.cffi import ffi
|
from pyarrow.cffi import ffi
|
||||||
|
|
||||||
from .utils import is_gzipped, tmpfile
|
from ..utils import is_gzipped, tmpfile
|
||||||
from .. import Pattern, Ref, PatternError, LibraryError, Label, Shape
|
from ... import Pattern, Ref, PatternError, LibraryError, Label, Shape
|
||||||
from ..shapes import Polygon, Path, PolyCollection, RectCollection
|
from ...shapes import Polygon, Path, PolyCollection, RectCollection
|
||||||
from ..repetition import Grid
|
from ...repetition import Grid
|
||||||
from ..utils import layer_t, annotations_t
|
from ...utils import layer_t, annotations_t
|
||||||
from ..library import LazyLibrary, Library, ILibrary, ILibraryView
|
from ...library import LazyLibrary, Library, ILibrary, ILibraryView
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
@ -136,7 +136,7 @@ def _installed_library_candidates() -> list[pathlib.Path]:
|
||||||
|
|
||||||
|
|
||||||
def _repo_library_candidates() -> list[pathlib.Path]:
|
def _repo_library_candidates() -> list[pathlib.Path]:
|
||||||
repo_root = pathlib.Path(__file__).resolve().parents[2]
|
repo_root = pathlib.Path(__file__).resolve().parents[3]
|
||||||
library_name = _local_library_filename()
|
library_name = _local_library_filename()
|
||||||
return [
|
return [
|
||||||
repo_root / 'klamath-rs' / 'target' / 'release' / library_name,
|
repo_root / 'klamath-rs' / 'target' / 'release' / library_name,
|
||||||
|
|
@ -167,7 +167,7 @@ def is_available() -> bool:
|
||||||
|
|
||||||
|
|
||||||
def _get_clib() -> Any:
|
def _get_clib() -> Any:
|
||||||
global clib
|
global clib # noqa: PLW0603
|
||||||
if clib is None:
|
if clib is None:
|
||||||
lib_path = find_klamath_rs_library()
|
lib_path = find_klamath_rs_library()
|
||||||
if lib_path is None:
|
if lib_path is None:
|
||||||
|
|
@ -33,12 +33,12 @@ from numpy.typing import ArrayLike, NDArray
|
||||||
import klamath
|
import klamath
|
||||||
from klamath import records
|
from klamath import records
|
||||||
|
|
||||||
from .utils import is_gzipped, tmpfile
|
from ..utils import is_gzipped, tmpfile
|
||||||
from .. import Pattern, Ref, PatternError, LibraryError, Label, Shape
|
from ... import Pattern, Ref, PatternError, LibraryError, Label, Shape
|
||||||
from ..shapes import Polygon, Path, RectCollection
|
from ...shapes import Polygon, Path, RectCollection
|
||||||
from ..repetition import Grid
|
from ...repetition import Grid
|
||||||
from ..utils import layer_t, annotations_t
|
from ...utils import layer_t, annotations_t
|
||||||
from ..library import Library, ILibrary
|
from ...library import Library, ILibrary
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
@ -10,7 +10,7 @@ This module provides the non-Arrow half of Masque's lazy GDS architecture:
|
||||||
- the source can be wrapped in `PortsLibraryView` or merged through
|
- the source can be wrapped in `PortsLibraryView` or merged through
|
||||||
`OverlayLibrary`
|
`OverlayLibrary`
|
||||||
|
|
||||||
The public surface intentionally parallels `gdsii_lazy_arrow` closely so that
|
The public surface intentionally parallels `gdsii.lazy_arrow` closely so that
|
||||||
callers can swap between the classic and Arrow-backed implementations with
|
callers can swap between the classic and Arrow-backed implementations with
|
||||||
minimal changes.
|
minimal changes.
|
||||||
"""
|
"""
|
||||||
|
|
@ -29,24 +29,24 @@ import klamath
|
||||||
import numpy
|
import numpy
|
||||||
from klamath import records
|
from klamath import records
|
||||||
|
|
||||||
from . import gdsii
|
from . import klamath as gdsii
|
||||||
from .utils import is_gzipped
|
from .lazy_write import write as write, writefile as writefile
|
||||||
from .gdsii_lazy_core import write as write, writefile as writefile
|
from ..utils import is_gzipped
|
||||||
from ..error import LibraryError
|
from ...error import LibraryError
|
||||||
from ..library import (
|
from ...library import (
|
||||||
ILibraryView,
|
ILibraryView,
|
||||||
LibraryView,
|
LibraryView,
|
||||||
PortsLibraryView,
|
PortsLibraryView,
|
||||||
dangling_mode_t,
|
dangling_mode_t,
|
||||||
)
|
)
|
||||||
from ..utils import apply_transforms
|
from ...utils import apply_transforms
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from collections.abc import Iterator, Sequence
|
from collections.abc import Iterator, Sequence
|
||||||
|
|
||||||
from numpy.typing import NDArray
|
from numpy.typing import NDArray
|
||||||
|
|
||||||
from ..pattern import Pattern
|
from ...pattern import Pattern
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"""
|
"""
|
||||||
Lazy GDSII readers and writers backed by native Arrow scan/materialize paths.
|
Lazy GDSII readers and writers backed by native Arrow scan/materialize paths.
|
||||||
|
|
||||||
This module is intentionally separate from `gdsii_arrow` so the eager read path
|
This module is intentionally separate from `gdsii.arrow` so the eager read path
|
||||||
keeps its current behavior and performance profile.
|
keeps its current behavior and performance profile.
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
@ -16,16 +16,16 @@ import pathlib
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
|
|
||||||
from . import gdsii_arrow
|
from . import arrow
|
||||||
from .utils import is_gzipped
|
from .lazy_write import write as write, writefile as writefile
|
||||||
from .gdsii_lazy_core import write as write, writefile as writefile
|
from ..utils import is_gzipped
|
||||||
from ..library import (
|
from ...library import (
|
||||||
ILibraryView,
|
ILibraryView,
|
||||||
LibraryView,
|
LibraryView,
|
||||||
PortsLibraryView,
|
PortsLibraryView,
|
||||||
dangling_mode_t,
|
dangling_mode_t,
|
||||||
)
|
)
|
||||||
from ..utils import apply_transforms
|
from ...utils import apply_transforms
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from collections.abc import Iterator, Sequence
|
from collections.abc import Iterator, Sequence
|
||||||
|
|
@ -33,7 +33,7 @@ if TYPE_CHECKING:
|
||||||
from numpy.typing import NDArray
|
from numpy.typing import NDArray
|
||||||
import pyarrow
|
import pyarrow
|
||||||
|
|
||||||
from ..pattern import Pattern
|
from ...pattern import Pattern
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
@ -87,11 +87,11 @@ class _ScanPayload:
|
||||||
refs: _ScanRefs
|
refs: _ScanRefs
|
||||||
|
|
||||||
def is_available() -> bool:
|
def is_available() -> bool:
|
||||||
return gdsii_arrow.is_available()
|
return arrow.is_available()
|
||||||
|
|
||||||
|
|
||||||
def _read_header(libarr: pyarrow.StructScalar) -> dict[str, Any]:
|
def _read_header(libarr: pyarrow.StructScalar) -> dict[str, Any]:
|
||||||
return gdsii_arrow._read_header(libarr)
|
return arrow._read_header(libarr)
|
||||||
|
|
||||||
|
|
||||||
def _open_source_buffer(path: pathlib.Path) -> _SourceBuffer:
|
def _open_source_buffer(path: pathlib.Path) -> _SourceBuffer:
|
||||||
|
|
@ -119,10 +119,10 @@ def _extract_scan_payload(libarr: pyarrow.StructScalar) -> _ScanPayload:
|
||||||
ref_values = refs.values
|
ref_values = refs.values
|
||||||
ref_offsets = refs.offsets.to_numpy()
|
ref_offsets = refs.offsets.to_numpy()
|
||||||
targets = ref_values.field('target').to_numpy()
|
targets = ref_values.field('target').to_numpy()
|
||||||
xy = gdsii_arrow._packed_xy_u64_to_pairs(ref_values.field('xy').to_numpy())
|
xy = arrow._packed_xy_u64_to_pairs(ref_values.field('xy').to_numpy())
|
||||||
xy0 = gdsii_arrow._packed_xy_u64_to_pairs(ref_values.field('xy0').to_numpy())
|
xy0 = arrow._packed_xy_u64_to_pairs(ref_values.field('xy0').to_numpy())
|
||||||
xy1 = gdsii_arrow._packed_xy_u64_to_pairs(ref_values.field('xy1').to_numpy())
|
xy1 = arrow._packed_xy_u64_to_pairs(ref_values.field('xy1').to_numpy())
|
||||||
counts = gdsii_arrow._packed_counts_u32_to_pairs(ref_values.field('counts').to_numpy())
|
counts = arrow._packed_counts_u32_to_pairs(ref_values.field('counts').to_numpy())
|
||||||
invert_y = ref_values.field('invert_y').to_numpy(zero_copy_only=False)
|
invert_y = ref_values.field('invert_y').to_numpy(zero_copy_only=False)
|
||||||
angle_rad = ref_values.field('angle_rad').to_numpy()
|
angle_rad = ref_values.field('angle_rad').to_numpy()
|
||||||
scale = ref_values.field('scale').to_numpy()
|
scale = ref_values.field('scale').to_numpy()
|
||||||
|
|
@ -228,7 +228,7 @@ class ArrowLibrary(ILibraryView):
|
||||||
def from_file(cls, filename: str | pathlib.Path) -> ArrowLibrary:
|
def from_file(cls, filename: str | pathlib.Path) -> ArrowLibrary:
|
||||||
path = pathlib.Path(filename).expanduser().resolve()
|
path = pathlib.Path(filename).expanduser().resolve()
|
||||||
source = _open_source_buffer(path)
|
source = _open_source_buffer(path)
|
||||||
scan_arr = gdsii_arrow._scan_buffer_to_arrow(source.data)
|
scan_arr = arrow._scan_buffer_to_arrow(source.data)
|
||||||
assert len(scan_arr) == 1
|
assert len(scan_arr) == 1
|
||||||
payload = _extract_scan_payload(scan_arr[0])
|
payload = _extract_scan_payload(scan_arr[0])
|
||||||
return cls(path=path, payload=payload, source=source)
|
return cls(path=path, payload=payload, source=source)
|
||||||
|
|
@ -288,9 +288,9 @@ class ArrowLibrary(ILibraryView):
|
||||||
],
|
],
|
||||||
dtype=numpy.uint64,
|
dtype=numpy.uint64,
|
||||||
)
|
)
|
||||||
arrow_arr = gdsii_arrow._read_selected_cells_to_arrow(self._source.data, ranges)
|
arrow_arr = arrow._read_selected_cells_to_arrow(self._source.data, ranges)
|
||||||
assert len(arrow_arr) == 1
|
assert len(arrow_arr) == 1
|
||||||
selected_lib, _info = gdsii_arrow.read_arrow(arrow_arr[0])
|
selected_lib, _info = arrow.read_arrow(arrow_arr[0])
|
||||||
for name in uncached:
|
for name in uncached:
|
||||||
pat = selected_lib[name]
|
pat = selected_lib[name]
|
||||||
materialized[name] = pat
|
materialized[name] = pat
|
||||||
|
|
@ -15,16 +15,16 @@ import pathlib
|
||||||
|
|
||||||
import klamath
|
import klamath
|
||||||
|
|
||||||
from . import gdsii
|
from . import klamath as gdsii
|
||||||
from .utils import tmpfile
|
from ..utils import tmpfile
|
||||||
from ..error import LibraryError
|
from ...error import LibraryError
|
||||||
from ..library import ILibraryView, OverlayLibrary
|
from ...library import ILibraryView, OverlayLibrary
|
||||||
from ..library.overlay import _SourceEntry, _materialize_detached_pattern
|
from ...library.overlay import _SourceEntry, _materialize_detached_pattern
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from collections.abc import Iterator, Mapping
|
from collections.abc import Iterator, Mapping
|
||||||
|
|
||||||
from ..pattern import Pattern
|
from ...pattern import Pattern
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
@ -244,7 +244,7 @@ def _annotation(index: int) -> dict[int, bytes]:
|
||||||
return {1: f'perf-{index}'.encode('ASCII')}
|
return {1: f'perf-{index}'.encode('ASCII')}
|
||||||
|
|
||||||
|
|
||||||
def _make_box_cell(name: str, index: int, cfg: FixturePreset) -> list[elements.Element]:
|
def _make_box_cell(index: int, cfg: FixturePreset) -> list[elements.Element]:
|
||||||
cell_elements: list[elements.Element] = []
|
cell_elements: list[elements.Element] = []
|
||||||
xbase = (index % 17) * 600
|
xbase = (index % 17) * 600
|
||||||
ybase = (index // 17) * 180
|
ybase = (index // 17) * 180
|
||||||
|
|
@ -277,7 +277,7 @@ def _make_box_cell(name: str, index: int, cfg: FixturePreset) -> list[elements.E
|
||||||
return cell_elements
|
return cell_elements
|
||||||
|
|
||||||
|
|
||||||
def _make_poly_cell(name: str, index: int, cfg: FixturePreset) -> list[elements.Element]:
|
def _make_poly_cell(index: int, cfg: FixturePreset) -> list[elements.Element]:
|
||||||
cell_elements: list[elements.Element] = []
|
cell_elements: list[elements.Element] = []
|
||||||
xbase = (index % 19) * 900
|
xbase = (index % 19) * 900
|
||||||
ybase = (index // 19) * 260
|
ybase = (index // 19) * 260
|
||||||
|
|
@ -368,12 +368,12 @@ def _poly_cluster_name(index: int) -> str:
|
||||||
|
|
||||||
def _write_box_cells(stream: Any, cfg: FixturePreset) -> None:
|
def _write_box_cells(stream: Any, cfg: FixturePreset) -> None:
|
||||||
for idx in range(cfg.box_cells):
|
for idx in range(cfg.box_cells):
|
||||||
_write_struct(stream, _box_name(idx), _make_box_cell(_box_name(idx), idx, cfg))
|
_write_struct(stream, _box_name(idx), _make_box_cell(idx, cfg))
|
||||||
|
|
||||||
|
|
||||||
def _write_poly_cells(stream: Any, cfg: FixturePreset) -> None:
|
def _write_poly_cells(stream: Any, cfg: FixturePreset) -> None:
|
||||||
for idx in range(cfg.poly_cells):
|
for idx in range(cfg.poly_cells):
|
||||||
_write_struct(stream, _poly_name(idx), _make_poly_cell(_poly_name(idx), idx, cfg))
|
_write_struct(stream, _poly_name(idx), _make_poly_cell(idx, cfg))
|
||||||
|
|
||||||
|
|
||||||
def _write_wrappers(stream: Any, cfg: FixturePreset) -> None:
|
def _write_wrappers(stream: Any, cfg: FixturePreset) -> None:
|
||||||
|
|
@ -14,8 +14,9 @@ from ..library import Library
|
||||||
from ..pattern import Pattern
|
from ..pattern import Pattern
|
||||||
from ..repetition import Grid
|
from ..repetition import Grid
|
||||||
from ..shapes import Path as MPath, Polygon, PolyCollection, RectCollection
|
from ..shapes import Path as MPath, Polygon, PolyCollection, RectCollection
|
||||||
from ..file import gdsii, gdsii_arrow
|
from ..file import gdsii
|
||||||
from ..file.gdsii_perf import write_fixture
|
from ..file.gdsii import arrow as gdsii_arrow
|
||||||
|
from ..file.gdsii.perf import write_fixture
|
||||||
|
|
||||||
|
|
||||||
if not gdsii_arrow.is_available():
|
if not gdsii_arrow.is_available():
|
||||||
|
|
@ -267,7 +268,7 @@ def test_gdsii_arrow_invalid_input_raises_klamath_error(tmp_path: Path) -> None:
|
||||||
gds_file.write_bytes(b'not-a-gds')
|
gds_file.write_bytes(b'not-a-gds')
|
||||||
|
|
||||||
script = textwrap.dedent(f"""
|
script = textwrap.dedent(f"""
|
||||||
from masque.file import gdsii_arrow
|
from masque.file.gdsii import arrow as gdsii_arrow
|
||||||
try:
|
try:
|
||||||
gdsii_arrow.readfile({str(gds_file)!r})
|
gdsii_arrow.readfile({str(gds_file)!r})
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ import numpy
|
||||||
import pytest
|
import pytest
|
||||||
from numpy.testing import assert_allclose
|
from numpy.testing import assert_allclose
|
||||||
|
|
||||||
from ..file import gdsii, gdsii_lazy
|
from ..file import gdsii
|
||||||
|
from ..file.gdsii import lazy as gdsii_lazy
|
||||||
from ..pattern import Pattern
|
from ..pattern import Pattern
|
||||||
from ..library import Library, OverlayLibrary
|
from ..library import Library, OverlayLibrary
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,9 @@ from .. import PatternError
|
||||||
from ..library import Library, OverlayLibrary
|
from ..library import Library, OverlayLibrary
|
||||||
from ..pattern import Pattern
|
from ..pattern import Pattern
|
||||||
from ..repetition import Grid
|
from ..repetition import Grid
|
||||||
from ..file import gdsii, gdsii_lazy_arrow
|
from ..file import gdsii
|
||||||
from ..file.gdsii_perf import write_fixture
|
from ..file.gdsii import lazy_arrow as gdsii_lazy_arrow
|
||||||
|
from ..file.gdsii.perf import write_fixture
|
||||||
|
|
||||||
|
|
||||||
if not gdsii_lazy_arrow.is_available():
|
if not gdsii_lazy_arrow.is_available():
|
||||||
|
|
@ -177,7 +178,7 @@ def test_gdsii_lazy_arrow_invalid_input_raises_klamath_error(tmp_path: Path) ->
|
||||||
gds_file.write_bytes(b'not-a-gds')
|
gds_file.write_bytes(b'not-a-gds')
|
||||||
|
|
||||||
script = textwrap.dedent(f"""
|
script = textwrap.dedent(f"""
|
||||||
from masque.file import gdsii_lazy_arrow
|
from masque.file.gdsii import lazy_arrow as gdsii_lazy_arrow
|
||||||
try:
|
try:
|
||||||
gdsii_lazy_arrow.readfile({str(gds_file)!r})
|
gdsii_lazy_arrow.readfile({str(gds_file)!r})
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from ..file import gdsii
|
from ..file import gdsii
|
||||||
from ..file.gdsii_perf import fixture_manifest, write_fixture
|
from ..file.gdsii.perf import fixture_manifest, write_fixture
|
||||||
|
|
||||||
|
|
||||||
def test_gdsii_perf_fixture_smoke(tmp_path: Path) -> None:
|
def test_gdsii_perf_fixture_smoke(tmp_path: Path) -> None:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue