[Builder / RenderPather] BREAKING remove aliases to old names
This commit is contained in:
parent
02f0833fb3
commit
778b3d9be7
18 changed files with 131 additions and 153 deletions
54
MIGRATION.md
54
MIGRATION.md
|
|
@ -18,11 +18,17 @@ The biggest migration point is that the old routing verbs were renamed:
|
|||
| `Pather.path(...)` | `Pather.trace(...)` |
|
||||
| `Pather.path_to(...)` | `Pather.trace_to(...)` |
|
||||
| `Pather.mpath(...)` | `Pather.trace(...)` / `Pather.trace_to(...)` with multiple ports |
|
||||
| `Pather.pathS(...)` | `Pather.jog(...)` |
|
||||
| `Pather.pathU(...)` | `Pather.uturn(...)` |
|
||||
| `Pather.path_into(...)` | `Pather.trace_into(...)` |
|
||||
| `RenderPather.path(...)` | `RenderPather.trace(...)` |
|
||||
| `RenderPather.path_to(...)` | `RenderPather.trace_to(...)` |
|
||||
| `RenderPather.mpath(...)` | `RenderPather.trace(...)` / `RenderPather.trace_to(...)` |
|
||||
| `RenderPather.path_into(...)` | `RenderPather.trace_into(...)` |
|
||||
| `Pather.path_from(src, dst)` | `Pather.at(src).trace_into(dst)` |
|
||||
| `RenderPather.path(...)` | `Pather(..., auto_render=False).trace(...)` |
|
||||
| `RenderPather.path_to(...)` | `Pather(..., auto_render=False).trace_to(...)` |
|
||||
| `RenderPather.mpath(...)` | `Pather(..., auto_render=False).trace(...)` / `Pather(..., auto_render=False).trace_to(...)` |
|
||||
| `RenderPather.pathS(...)` | `Pather(..., auto_render=False).jog(...)` |
|
||||
| `RenderPather.pathU(...)` | `Pather(..., auto_render=False).uturn(...)` |
|
||||
| `RenderPather.path_into(...)` | `Pather(..., auto_render=False).trace_into(...)` |
|
||||
| `RenderPather.path_from(src, dst)` | `Pather(..., auto_render=False).at(src).trace_into(dst)` |
|
||||
|
||||
There are also new convenience wrappers:
|
||||
|
||||
|
|
@ -43,13 +49,19 @@ that still calls `pather.path(...)` must be renamed.
|
|||
pather.path('VCC', False, 6_000)
|
||||
pather.path_to('VCC', None, x=0)
|
||||
pather.mpath(['GND', 'VCC'], True, xmax=-10_000, spacing=5_000)
|
||||
pather.pathS('VCC', offset=-2_000, length=8_000)
|
||||
pather.pathU('VCC', offset=4_000, length=5_000)
|
||||
pather.path_into('src', 'dst')
|
||||
pather.path_from('src', 'dst')
|
||||
|
||||
# new
|
||||
pather.cw('VCC', 6_000)
|
||||
pather.straight('VCC', x=0)
|
||||
pather.ccw(['GND', 'VCC'], xmax=-10_000, spacing=5_000)
|
||||
pather.jog('VCC', offset=-2_000, length=8_000)
|
||||
pather.uturn('VCC', offset=4_000, length=5_000)
|
||||
pather.trace_into('src', 'dst')
|
||||
pather.at('src').trace_into('dst')
|
||||
```
|
||||
|
||||
If you prefer the more explicit spelling, `trace(...)` and `trace_to(...)`
|
||||
|
|
@ -73,11 +85,30 @@ Routing can now be written in a fluent style via `.at(...)`, which returns a
|
|||
```
|
||||
|
||||
This is additive, not required for migration. Existing code can stay with the
|
||||
non-fluent `Pather`/`RenderPather` methods after renaming the verbs above.
|
||||
non-fluent `Pather` methods after renaming the verbs above.
|
||||
|
||||
Old `PortPather` helper names were also cleaned up:
|
||||
|
||||
| Old API | New API |
|
||||
| --- | --- |
|
||||
| `save_copy(...)` | `mark(...)` |
|
||||
| `rename_to(...)` | `rename(...)` |
|
||||
|
||||
Example:
|
||||
|
||||
```python
|
||||
# old
|
||||
pp.save_copy('branch')
|
||||
pp.rename_to('feed')
|
||||
|
||||
# new
|
||||
pp.mark('branch')
|
||||
pp.rename('feed')
|
||||
```
|
||||
|
||||
## Imports and module layout
|
||||
|
||||
`Builder`, `Pather`, and `RenderPather` now live together in
|
||||
`Pather` now provides the remaining builder/routing surface in
|
||||
`masque/builder/pather.py`. The old module files
|
||||
`masque/builder/builder.py` and `masque/builder/renderpather.py` were removed.
|
||||
|
||||
|
|
@ -89,14 +120,17 @@ from masque.builder.builder import Builder
|
|||
from masque.builder.renderpather import RenderPather
|
||||
|
||||
# new
|
||||
from masque.builder import Builder, RenderPather
|
||||
from masque.builder import Pather
|
||||
|
||||
builder = Pather(...)
|
||||
deferred = Pather(..., auto_render=False)
|
||||
```
|
||||
|
||||
Top-level imports from `masque` also continue to work.
|
||||
|
||||
`Builder` is now a thin compatibility wrapper over the unified `Pather`
|
||||
implementation with `auto_render=True`. `RenderPather` is the same wrapper with
|
||||
`auto_render=False`.
|
||||
`Pather` now defaults to `auto_render=True`, so plain construction replaces the
|
||||
old `Builder` behavior. Use `Pather(..., auto_render=False)` where you
|
||||
previously used `RenderPather`.
|
||||
|
||||
## `BasicTool` was replaced
|
||||
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ References are accomplished by listing the target's name, not its `Pattern` obje
|
|||
in order to create a reference, but they also need to access the pattern's ports.
|
||||
* One way to provide this data is through an `Abstract`, generated via
|
||||
`Library.abstract()` or through a `Library.abstract_view()`.
|
||||
* Another way is use `Builder.place()` or `Builder.plug()`, which automatically creates
|
||||
* Another way is use `Pather.place()` or `Pather.plug()`, which automatically creates
|
||||
an `Abstract` from its internally-referenced `Library`.
|
||||
|
||||
|
||||
|
|
@ -193,8 +193,8 @@ my_pattern.ref(new_name, ...) # instantiate the cell
|
|||
# In practice, you may do lots of
|
||||
my_pattern.ref(lib << make_tree(...), ...)
|
||||
|
||||
# With a `Builder` and `place()`/`plug()` the `lib <<` portion can be implicit:
|
||||
my_builder = Builder(library=lib, ...)
|
||||
# With a `Pather` and `place()`/`plug()` the `lib <<` portion can be implicit:
|
||||
my_builder = Pather(library=lib, ...)
|
||||
...
|
||||
my_builder.place(make_tree(...))
|
||||
```
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ Contents
|
|||
* Build hierarchical photonic-crystal example devices
|
||||
* Reference other patterns
|
||||
* Add ports to a pattern
|
||||
* Use `Builder` to snap ports together into a circuit
|
||||
* Use `Pather` to snap ports together into a circuit
|
||||
* Check for dangling references
|
||||
- [library](library.py)
|
||||
* Continue from `devices.py` using a lazy library
|
||||
|
|
@ -29,7 +29,7 @@ Contents
|
|||
* Use `AutoTool` to generate paths
|
||||
* Use `AutoTool` to automatically transition between path types
|
||||
- [renderpather](renderpather.py)
|
||||
* Use `RenderPather` and `PathTool` to build a layout similar to the one in [pather](pather.py),
|
||||
* Use `Pather(auto_render=False)` and `PathTool` to build a layout similar to the one in [pather](pather.py),
|
||||
but using `Path` shapes instead of `Polygon`s.
|
||||
- [port_pather](port_pather.py)
|
||||
* Use `PortPather` and the `.at()` syntax for more concise routing
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
Tutorial: building hierarchical devices with `Pattern`, `Port`, and `Builder`.
|
||||
Tutorial: building hierarchical devices with `Pattern`, `Port`, and `Pather`.
|
||||
|
||||
This file uses photonic-crystal components as the concrete example, so some of
|
||||
the geometry-generation code is domain-specific. The tutorial value is in the
|
||||
|
|
@ -12,7 +12,7 @@ import numpy
|
|||
from numpy import pi
|
||||
|
||||
from masque import (
|
||||
layer_t, Pattern, Ref, Builder, Port, Polygon,
|
||||
layer_t, Pattern, Ref, Pather, Port, Polygon,
|
||||
Library,
|
||||
)
|
||||
from masque.utils import ports2data
|
||||
|
|
@ -261,8 +261,8 @@ def main(interactive: bool = True) -> None:
|
|||
#
|
||||
# Build a circuit
|
||||
#
|
||||
# Create a `Builder`, and register the resulting top cell as "my_circuit".
|
||||
circ = Builder(library=lib, name='my_circuit')
|
||||
# Create a `Pather`, and register the resulting top cell as "my_circuit".
|
||||
circ = Pather(library=lib, name='my_circuit')
|
||||
|
||||
# Start by placing a waveguide and renaming its ports to match the circuit-level
|
||||
# names we want to use while assembling the design.
|
||||
|
|
@ -278,7 +278,7 @@ def main(interactive: bool = True) -> None:
|
|||
# lib['my_circuit'] = circ_pat
|
||||
# circ_pat.place(lib.abstract('wg10'), ...)
|
||||
# circ_pat.plug(lib.abstract('wg10'), ...)
|
||||
# but `Builder` removes some repeated `lib.abstract(...)` boilerplate and keeps
|
||||
# but `Pather` removes some repeated `lib.abstract(...)` boilerplate and keeps
|
||||
# the assembly code focused on port-level intent.
|
||||
|
||||
# Attach a y-splitter to the signal path.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
Tutorial: using `LazyLibrary` and `Builder.interface()`.
|
||||
Tutorial: using `LazyLibrary` and `Pather.interface()`.
|
||||
|
||||
This example assumes you have already read `devices.py` and generated the
|
||||
`circuit.gds` file it writes. The goal here is not the photonic-crystal geometry
|
||||
|
|
@ -10,7 +10,7 @@ from typing import Any
|
|||
from pprint import pformat
|
||||
|
||||
|
||||
from masque import Builder, LazyLibrary
|
||||
from masque import Pather, LazyLibrary
|
||||
from masque.file.gdsii import writefile, load_libraryfile
|
||||
|
||||
import basic_shapes
|
||||
|
|
@ -64,10 +64,10 @@ def main() -> None:
|
|||
|
||||
# Start a new design by copying the ports from an existing library cell.
|
||||
# This gives `circ2` the same external interface as `tri_l3cav`.
|
||||
circ2 = Builder(library=lib, ports='tri_l3cav')
|
||||
circ2 = Pather(library=lib, ports='tri_l3cav')
|
||||
|
||||
# First way to specify what we are plugging in: request an explicit abstract.
|
||||
# This works with `Pattern` methods directly as well as with `Builder`.
|
||||
# This works with `Pattern` methods directly as well as with `Pather`.
|
||||
circ2.plug(lib.abstract('wg10'), {'input': 'right'})
|
||||
|
||||
# Second way: use an `AbstractView`, which behaves like a mapping of names
|
||||
|
|
@ -75,7 +75,7 @@ def main() -> None:
|
|||
abstracts = lib.abstract_view()
|
||||
circ2.plug(abstracts['wg10'], {'output': 'left'})
|
||||
|
||||
# Third way: let `Builder` resolve a pattern name through its own library.
|
||||
# Third way: let `Pather` resolve a pattern name through its own library.
|
||||
# This shorthand is convenient, but it is specific to helpers that already
|
||||
# carry a library reference.
|
||||
circ2.plug('tri_wg10', {'input': 'right'})
|
||||
|
|
@ -89,10 +89,10 @@ def main() -> None:
|
|||
# Build a second device that is explicitly designed to mate with `circ2`.
|
||||
#
|
||||
|
||||
# `Builder.interface()` makes a new pattern whose ports mirror an existing
|
||||
# `Pather.interface()` makes a new pattern whose ports mirror an existing
|
||||
# design's external interface. That is useful when you want to design an
|
||||
# adapter, continuation, or mating structure.
|
||||
circ3 = Builder.interface(source=circ2)
|
||||
circ3 = Pather.interface(source=circ2)
|
||||
|
||||
# Continue routing outward from those inherited ports.
|
||||
circ3.plug('tri_bend0', {'input': 'right'})
|
||||
|
|
|
|||
|
|
@ -204,9 +204,9 @@ def prepare_tools() -> tuple[Library, Tool, Tool]:
|
|||
#
|
||||
# Now we can start building up our library (collection of static cells) and pathing tools.
|
||||
#
|
||||
# If any of the operations below are confusing, you can cross-reference against the `RenderPather`
|
||||
# tutorial, which handles some things more explicitly (e.g. via placement) and simplifies others
|
||||
# (e.g. geometry definition).
|
||||
# If any of the operations below are confusing, you can cross-reference against the deferred
|
||||
# `Pather` tutorial, which handles some things more explicitly (e.g. via placement) and simplifies
|
||||
# others (e.g. geometry definition).
|
||||
#
|
||||
def main() -> None:
|
||||
library, M1_tool, M2_tool = prepare_tools()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"""
|
||||
PortPather tutorial: Using .at() syntax
|
||||
"""
|
||||
from masque import RenderPather, Pattern, Port, R90
|
||||
from masque import Pather, Pattern, Port, R90
|
||||
from masque.file.gdsii import writefile
|
||||
|
||||
from basic_shapes import GDS_OPTS
|
||||
|
|
@ -12,8 +12,8 @@ def main() -> None:
|
|||
# Reuse the same patterns (pads, bends, vias) and tools as in pather.py
|
||||
library, M1_tool, M2_tool = prepare_tools()
|
||||
|
||||
# Create a RenderPather and place some initial pads (same as Pather tutorial)
|
||||
rpather = RenderPather(library, tools=M2_tool)
|
||||
# Create a deferred Pather and place some initial pads (same as Pather tutorial)
|
||||
rpather = Pather(library, tools=M2_tool, auto_render=False)
|
||||
|
||||
rpather.place('pad', offset=(18_000, 30_000), port_map={'wire_port': 'VCC'})
|
||||
rpather.place('pad', offset=(18_000, 60_000), port_map={'wire_port': 'GND'})
|
||||
|
|
@ -156,7 +156,7 @@ def main() -> None:
|
|||
#
|
||||
# Rendering and Saving
|
||||
#
|
||||
# Since we used RenderPather, we must call .render() to generate the geometry.
|
||||
# Since we deferred auto-rendering, we must call .render() to generate the geometry.
|
||||
rpather.render()
|
||||
|
||||
library['PortPather_Tutorial'] = rpather.pattern
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"""
|
||||
Manual wire routing tutorial: RenderPather an PathTool
|
||||
Manual wire routing tutorial: deferred Pather and PathTool
|
||||
"""
|
||||
from masque import RenderPather, Library
|
||||
from masque import Pather, Library
|
||||
from masque.builder.tools import PathTool
|
||||
from masque.file.gdsii import writefile
|
||||
|
||||
|
|
@ -11,9 +11,9 @@ from pather import M1_WIDTH, V1_WIDTH, M2_WIDTH, map_layer, make_pad, make_via
|
|||
|
||||
def main() -> None:
|
||||
#
|
||||
# To illustrate the advantages of using `RenderPather`, we use `PathTool` instead
|
||||
# To illustrate deferred routing with `Pather`, we use `PathTool` instead
|
||||
# of `AutoTool`. `PathTool` lacks some sophistication (e.g. no automatic transitions)
|
||||
# but when used with `RenderPather`, it can consolidate multiple routing steps into
|
||||
# but when used with `Pather(auto_render=False)`, it can consolidate multiple routing steps into
|
||||
# a single `Path` shape.
|
||||
#
|
||||
# We'll try to nearly replicate the layout from the `Pather` tutorial; see `pather.py`
|
||||
|
|
@ -39,7 +39,7 @@ def main() -> None:
|
|||
# and what port type to present.
|
||||
M1_ptool = PathTool(layer='M1', width=M1_WIDTH, ptype='m1wire')
|
||||
M2_ptool = PathTool(layer='M2', width=M2_WIDTH, ptype='m2wire')
|
||||
rpather = RenderPather(tools=M2_ptool, library=library)
|
||||
rpather = Pather(tools=M2_ptool, library=library, auto_render=False)
|
||||
|
||||
# As in the pather tutorial, we make some pads and labels...
|
||||
rpather.place('pad', offset=(18_000, 30_000), port_map={'wire_port': 'VCC'})
|
||||
|
|
@ -85,7 +85,7 @@ def main() -> None:
|
|||
|
||||
# Render the path we defined
|
||||
rpather.render()
|
||||
library['RenderPather_and_PathTool'] = rpather.pattern
|
||||
library['Deferred_Pather_and_PathTool'] = rpather.pattern
|
||||
|
||||
|
||||
# Convert from text-based layers to numeric layers for GDS, and output the file
|
||||
|
|
|
|||
|
|
@ -73,10 +73,8 @@ from .ports import (
|
|||
)
|
||||
from .abstract import Abstract as Abstract
|
||||
from .builder import (
|
||||
Builder as Builder,
|
||||
Tool as Tool,
|
||||
Pather as Pather,
|
||||
RenderPather as RenderPather,
|
||||
RenderStep as RenderStep,
|
||||
SimpleTool as SimpleTool,
|
||||
AutoTool as AutoTool,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
from .pather import (
|
||||
Pather as Pather,
|
||||
PortPather as PortPather,
|
||||
Builder as Builder,
|
||||
RenderPather as RenderPather,
|
||||
)
|
||||
from .utils import ell as ell
|
||||
from .tools import (
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
Logging and operation decorators for Builder/Pather
|
||||
Logging and operation decorators for Pather
|
||||
"""
|
||||
from typing import TYPE_CHECKING, Any
|
||||
from collections.abc import Iterator, Sequence, Callable
|
||||
|
|
@ -31,7 +31,7 @@ def _format_log_args(**kwargs) -> str:
|
|||
|
||||
class PatherLogger:
|
||||
"""
|
||||
Encapsulates state for Pather/Builder diagnostic logging.
|
||||
Encapsulates state for Pather diagnostic logging.
|
||||
"""
|
||||
debug: bool
|
||||
indent: int
|
||||
|
|
@ -90,7 +90,7 @@ def logged_op(
|
|||
portspec_getter: Callable[[dict[str, Any]], str | Sequence[str] | None] | None = None,
|
||||
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
||||
"""
|
||||
Decorator to wrap Builder methods with logging.
|
||||
Decorator to wrap Pather methods with logging.
|
||||
"""
|
||||
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
|
||||
sig = inspect.signature(func)
|
||||
|
|
|
|||
|
|
@ -38,11 +38,9 @@ class Pather(PortList):
|
|||
The `Pather` holds context in the form of a `Library`, its underlying
|
||||
pattern, and a set of `Tool`s for generating routing segments.
|
||||
|
||||
Routing operations (`trace`, `jog`, `uturn`, etc.) are by default
|
||||
deferred: they record the intended path but do not immediately generate
|
||||
geometry. `render()` must be called to generate the final layout.
|
||||
Alternatively, setting `auto_render=True` in the constructor will
|
||||
cause geometry to be generated incrementally after each routing step.
|
||||
Routing operations (`trace`, `jog`, `uturn`, etc.) are rendered
|
||||
incrementally by default. Set `auto_render=False` to defer geometry
|
||||
generation until an explicit call to `render()`.
|
||||
|
||||
Examples: Creating a Pather
|
||||
===========================
|
||||
|
|
@ -58,8 +56,8 @@ class Pather(PortList):
|
|||
connects port 'A' of the current pattern to port 'C' of `subdevice`.
|
||||
|
||||
- `pather.trace('my_port', ccw=True, length=100)` plans a 100-unit bend
|
||||
starting at 'my_port'. If `auto_render=True`, geometry is added
|
||||
immediately. Otherwise, call `pather.render()` later.
|
||||
starting at 'my_port'. Geometry is added immediately by default.
|
||||
Set `auto_render=False` to defer and call `pather.render()` later.
|
||||
"""
|
||||
__slots__ = (
|
||||
'pattern', 'library', 'tools', 'paths',
|
||||
|
|
@ -118,7 +116,7 @@ class Pather(PortList):
|
|||
tools: Tool | MutableMapping[str | None, Tool] | None = None,
|
||||
name: str | None = None,
|
||||
debug: bool = False,
|
||||
auto_render: bool = False,
|
||||
auto_render: bool = True,
|
||||
auto_render_append: bool = True,
|
||||
) -> None:
|
||||
"""
|
||||
|
|
@ -1358,53 +1356,3 @@ class PortPather:
|
|||
self.pather.rename_ports({name: None})
|
||||
self.ports = [pp for pp in self.ports if pp != name]
|
||||
return self
|
||||
|
||||
|
||||
class Builder(Pather):
|
||||
"""
|
||||
Backward-compatible wrapper for Pather with auto_render=True.
|
||||
"""
|
||||
def __init__(
|
||||
self,
|
||||
library: ILibrary,
|
||||
*,
|
||||
pattern: Pattern | None = None,
|
||||
ports: str | Mapping[str, Port] | None = None,
|
||||
tools: Tool | MutableMapping[str | None, Tool] | None = None,
|
||||
name: str | None = None,
|
||||
debug: bool = False,
|
||||
) -> None:
|
||||
super().__init__(
|
||||
library=library,
|
||||
pattern=pattern,
|
||||
ports=ports,
|
||||
tools=tools,
|
||||
name=name,
|
||||
debug=debug,
|
||||
auto_render=True,
|
||||
)
|
||||
|
||||
|
||||
class RenderPather(Pather):
|
||||
"""
|
||||
Backward-compatible wrapper for Pather with auto_render=False.
|
||||
"""
|
||||
def __init__(
|
||||
self,
|
||||
library: ILibrary,
|
||||
*,
|
||||
pattern: Pattern | None = None,
|
||||
ports: str | Mapping[str, Port] | None = None,
|
||||
tools: Tool | MutableMapping[str | None, Tool] | None = None,
|
||||
name: str | None = None,
|
||||
debug: bool = False,
|
||||
) -> None:
|
||||
super().__init__(
|
||||
library=library,
|
||||
pattern=pattern,
|
||||
ports=ports,
|
||||
tools=tools,
|
||||
name=name,
|
||||
debug=debug,
|
||||
auto_render=False,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ from ..error import BuildError
|
|||
@dataclass(frozen=True, slots=True)
|
||||
class RenderStep:
|
||||
"""
|
||||
Representation of a single saved operation, used by `RenderPather` and passed
|
||||
to `Tool.render()` when `RenderPather.render()` is called.
|
||||
Representation of a single saved operation, used by deferred `Pather`
|
||||
instances and passed to `Tool.render()` when `Pather.render()` is called.
|
||||
"""
|
||||
opcode: Literal['L', 'S', 'U', 'P']
|
||||
""" What operation is being performed.
|
||||
|
|
@ -128,7 +128,7 @@ class Tool:
|
|||
Create a wire or waveguide that travels exactly `length` distance along the axis
|
||||
of its input port.
|
||||
|
||||
Used by `Pather` and `RenderPather`.
|
||||
Used by `Pather`.
|
||||
|
||||
The output port must be exactly `length` away along the input port's axis, but
|
||||
may be placed an additional (unspecified) distance away along the perpendicular
|
||||
|
|
@ -174,7 +174,7 @@ class Tool:
|
|||
of its input port, and `jog` distance on the perpendicular axis.
|
||||
`jog` is positive when moving left of the direction of travel (from input to ouput port).
|
||||
|
||||
Used by `Pather` and `RenderPather`.
|
||||
Used by `Pather`.
|
||||
|
||||
The output port should be rotated to face the input port (i.e. plugging the device
|
||||
into a port will move that port but keep its orientation).
|
||||
|
|
@ -214,7 +214,7 @@ class Tool:
|
|||
Plan a wire or waveguide that travels exactly `length` distance along the axis
|
||||
of its input port.
|
||||
|
||||
Used by `RenderPather`.
|
||||
Used by `Pather` when `auto_render=False`.
|
||||
|
||||
The output port must be exactly `length` away along the input port's axis, but
|
||||
may be placed an additional (unspecified) distance away along the perpendicular
|
||||
|
|
@ -266,7 +266,7 @@ class Tool:
|
|||
Plan a wire or waveguide that travels exactly `length` distance along the axis
|
||||
of its input port and `jog` distance along the perpendicular axis (i.e. an S-bend).
|
||||
|
||||
Used by `RenderPather`.
|
||||
Used by `Pather` when `auto_render=False`.
|
||||
|
||||
The output port must have an orientation rotated by pi from the input port.
|
||||
|
||||
|
|
@ -315,7 +315,7 @@ class Tool:
|
|||
Create a wire or waveguide that travels exactly `jog` distance along the axis
|
||||
perpendicular to its input port (i.e. a U-bend).
|
||||
|
||||
Used by `Pather` and `RenderPather`. Tools may leave this unimplemented if they
|
||||
Used by `Pather`. Tools may leave this unimplemented if they
|
||||
do not support a native U-bend primitive.
|
||||
|
||||
The output port must have an orientation identical to the input port.
|
||||
|
|
@ -354,7 +354,7 @@ class Tool:
|
|||
Plan a wire or waveguide that travels exactly `jog` distance along the axis
|
||||
perpendicular to its input port (i.e. a U-bend).
|
||||
|
||||
Used by `RenderPather`. This is an optional native-planning hook: tools may
|
||||
Used by `Pather` when `auto_render=False`. This is an optional native-planning hook: tools may
|
||||
implement it when they can represent a U-turn directly, otherwise they may rely
|
||||
on `traceU()` or let `Pather` synthesize the route from simpler primitives.
|
||||
|
||||
|
|
@ -1323,7 +1323,7 @@ class PathTool(Tool, metaclass=ABCMeta):
|
|||
|
||||
# Transform the batch so the first port is local (at 0,0) but retains its global rotation.
|
||||
# This allows the path to be rendered with its original orientation, simplified by
|
||||
# translation to the origin. RenderPather.render will handle the final placement
|
||||
# translation to the origin. Pather.render will handle the final placement
|
||||
# (including rotation alignment) via `pat.plug`.
|
||||
first_port = batch[0].start_port
|
||||
translation = -first_port.offset
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||
or provide equivalent functions.
|
||||
|
||||
`Pattern` also stores a dict of `Port`s, which can be used to "snap" together points.
|
||||
See `Pattern.plug()` and `Pattern.place()`, as well as the helper classes
|
||||
`builder.Builder`, `builder.Pather`, `builder.RenderPather`, and `ports.PortsList`.
|
||||
See `Pattern.plug()` and `Pattern.place()`, as well as `builder.Pather`
|
||||
and `ports.PortsList`.
|
||||
|
||||
For convenience, ports can be read out using square brackets:
|
||||
- `pattern['A'] == Port((0, 0), 0)`
|
||||
|
|
@ -1664,7 +1664,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||
current device.
|
||||
|
||||
Args:
|
||||
source: A collection of ports (e.g. Pattern, Builder, or dict)
|
||||
source: A collection of ports (e.g. Pattern, Pather, or dict)
|
||||
from which to create the interface.
|
||||
in_prefix: Prepended to port names for newly-created ports with
|
||||
reversed directions compared to the current device.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from masque.builder.tools import AutoTool
|
|||
from masque.pattern import Pattern
|
||||
from masque.ports import Port
|
||||
from masque.library import Library
|
||||
from masque.builder.pather import Pather, RenderPather
|
||||
from masque.builder.pather import Pather
|
||||
|
||||
def make_straight(length, width=2, ptype="wire"):
|
||||
pat = Pattern()
|
||||
|
|
@ -166,7 +166,7 @@ def test_autotool_planS_pure_sbend_with_transition_dx() -> None:
|
|||
|
||||
def test_renderpather_autotool_double_L(multi_bend_tool) -> None:
|
||||
tool, lib = multi_bend_tool
|
||||
rp = RenderPather(lib, tools=tool)
|
||||
rp = Pather(lib, tools=tool, auto_render=False)
|
||||
rp.ports["A"] = Port((0,0), 0, ptype="wire")
|
||||
|
||||
# This should trigger double-L fallback in planS
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import pytest
|
|||
from numpy.testing import assert_equal, assert_allclose
|
||||
from numpy import pi
|
||||
|
||||
from ..builder import Builder
|
||||
from ..builder import Pather
|
||||
from ..builder.utils import ell
|
||||
from ..error import BuildError
|
||||
from ..library import Library
|
||||
|
|
@ -13,7 +13,7 @@ from ..ports import Port
|
|||
|
||||
def test_builder_init() -> None:
|
||||
lib = Library()
|
||||
b = Builder(lib, name="mypat")
|
||||
b = Pather(lib, name="mypat")
|
||||
assert b.pattern is lib["mypat"]
|
||||
assert b.library is lib
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ def test_builder_place() -> None:
|
|||
child.ports["A"] = Port((0, 0), 0)
|
||||
lib["child"] = child
|
||||
|
||||
b = Builder(lib)
|
||||
b = Pather(lib)
|
||||
b.place("child", offset=(10, 20), port_map={"A": "child_A"})
|
||||
|
||||
assert "child_A" in b.ports
|
||||
|
|
@ -40,7 +40,7 @@ def test_builder_plug() -> None:
|
|||
wire.ports["out"] = Port((10, 0), pi)
|
||||
lib["wire"] = wire
|
||||
|
||||
b = Builder(lib)
|
||||
b = Pather(lib)
|
||||
b.ports["start"] = Port((100, 100), 0)
|
||||
|
||||
# Plug wire's "in" port into builder's "start" port
|
||||
|
|
@ -64,7 +64,7 @@ def test_builder_interface() -> None:
|
|||
source.ports["P1"] = Port((0, 0), 0)
|
||||
lib["source"] = source
|
||||
|
||||
b = Builder.interface("source", library=lib, name="iface")
|
||||
b = Pather.interface("source", library=lib, name="iface")
|
||||
assert "in_P1" in b.ports
|
||||
assert "P1" in b.ports
|
||||
assert b.pattern is lib["iface"]
|
||||
|
|
@ -73,7 +73,7 @@ def test_builder_interface() -> None:
|
|||
def test_builder_set_dead() -> None:
|
||||
lib = Library()
|
||||
lib["sub"] = Pattern()
|
||||
b = Builder(lib)
|
||||
b = Pather(lib)
|
||||
b.set_dead()
|
||||
|
||||
b.place("sub")
|
||||
|
|
@ -84,7 +84,7 @@ def test_builder_dead_ports() -> None:
|
|||
lib = Library()
|
||||
pat = Pattern()
|
||||
pat.ports['A'] = Port((0, 0), 0)
|
||||
b = Builder(lib, pattern=pat)
|
||||
b = Pather(lib, pattern=pat)
|
||||
b.set_dead()
|
||||
|
||||
# Attempt to plug a device where ports don't line up
|
||||
|
|
@ -107,7 +107,7 @@ def test_dead_plug_best_effort() -> None:
|
|||
lib = Library()
|
||||
pat = Pattern()
|
||||
pat.ports['A'] = Port((0, 0), 0)
|
||||
b = Builder(lib, pattern=pat)
|
||||
b = Pather(lib, pattern=pat)
|
||||
b.set_dead()
|
||||
|
||||
# Device with multiple ports, none of which line up correctly
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ from typing import Any
|
|||
import pytest
|
||||
import numpy
|
||||
from numpy import pi
|
||||
from masque import Pather, RenderPather, Library, Pattern, Port
|
||||
from masque import Pather, Library, Pattern, Port
|
||||
from masque.builder.tools import PathTool, Tool
|
||||
from masque.error import BuildError, PortError, PatternError
|
||||
|
||||
def test_pather_trace_basic() -> None:
|
||||
lib = Library()
|
||||
tool = PathTool(layer='M1', width=1000)
|
||||
p = Pather(lib, tools=tool)
|
||||
p = Pather(lib, tools=tool, auto_render=False)
|
||||
|
||||
# Port rotation 0 points in +x (INTO device).
|
||||
# To extend it, we move in -x direction.
|
||||
|
|
@ -35,7 +35,7 @@ def test_pather_trace_basic() -> None:
|
|||
def test_pather_trace_to() -> None:
|
||||
lib = Library()
|
||||
tool = PathTool(layer='M1', width=1000)
|
||||
p = Pather(lib, tools=tool)
|
||||
p = Pather(lib, tools=tool, auto_render=False)
|
||||
|
||||
p.pattern.ports['A'] = Port((0, 0), rotation=0)
|
||||
|
||||
|
|
@ -50,7 +50,7 @@ def test_pather_trace_to() -> None:
|
|||
def test_pather_bundle_trace() -> None:
|
||||
lib = Library()
|
||||
tool = PathTool(layer='M1', width=1000)
|
||||
p = Pather(lib, tools=tool)
|
||||
p = Pather(lib, tools=tool, auto_render=False)
|
||||
|
||||
p.pattern.ports['A'] = Port((0, 0), rotation=0)
|
||||
p.pattern.ports['B'] = Port((0, 2000), rotation=0)
|
||||
|
|
@ -74,7 +74,7 @@ def test_pather_bundle_trace() -> None:
|
|||
def test_pather_each_bound() -> None:
|
||||
lib = Library()
|
||||
tool = PathTool(layer='M1', width=1000)
|
||||
p = Pather(lib, tools=tool)
|
||||
p = Pather(lib, tools=tool, auto_render=False)
|
||||
|
||||
p.pattern.ports['A'] = Port((0, 0), rotation=0)
|
||||
p.pattern.ports['B'] = Port((-1000, 2000), rotation=0)
|
||||
|
|
@ -198,7 +198,7 @@ def test_rename() -> None:
|
|||
def test_renderpather_uturn_fallback() -> None:
|
||||
lib = Library()
|
||||
tool = PathTool(layer='M1', width=1000)
|
||||
rp = RenderPather(lib, tools=tool)
|
||||
rp = Pather(lib, tools=tool, auto_render=False)
|
||||
rp.pattern.ports['A'] = Port((0, 0), rotation=0)
|
||||
|
||||
# PathTool doesn't implement planU, so it should fall back to two planL calls
|
||||
|
|
@ -239,7 +239,7 @@ def test_autotool_uturn() -> None:
|
|||
default_out_ptype='wire'
|
||||
)
|
||||
|
||||
p = Pather(lib, tools=tool)
|
||||
p = Pather(lib, tools=tool, auto_render=False)
|
||||
p.pattern.ports['A'] = Port((0, 0), 0)
|
||||
|
||||
# CW U-turn (jog < 0)
|
||||
|
|
@ -261,7 +261,7 @@ def test_autotool_uturn() -> None:
|
|||
def test_pather_trace_into() -> None:
|
||||
lib = Library()
|
||||
tool = PathTool(layer='M1', width=1000)
|
||||
p = Pather(lib, tools=tool)
|
||||
p = Pather(lib, tools=tool, auto_render=False)
|
||||
|
||||
# 1. Straight connector
|
||||
p.pattern.ports['A'] = Port((0, 0), rotation=0)
|
||||
|
|
@ -313,7 +313,7 @@ def test_pather_trace_into() -> None:
|
|||
def test_pather_trace_into_dead_updates_ports_without_geometry() -> None:
|
||||
lib = Library()
|
||||
tool = PathTool(layer='M1', width=1000, ptype='wire')
|
||||
p = Pather(lib, tools=tool)
|
||||
p = Pather(lib, tools=tool, auto_render=False)
|
||||
p.pattern.ports['A'] = Port((0, 0), rotation=0, ptype='wire')
|
||||
p.pattern.ports['B'] = Port((-10000, 0), rotation=pi, ptype='wire')
|
||||
p.set_dead()
|
||||
|
|
@ -332,7 +332,7 @@ def test_pather_trace_into_dead_updates_ports_without_geometry() -> None:
|
|||
def test_pather_dead_fallback_preserves_out_ptype() -> None:
|
||||
lib = Library()
|
||||
tool = PathTool(layer='M1', width=1000, ptype='wire')
|
||||
p = Pather(lib, tools=tool)
|
||||
p = Pather(lib, tools=tool, auto_render=False)
|
||||
p.pattern.ports['A'] = Port((0, 0), rotation=0, ptype='wire')
|
||||
p.set_dead()
|
||||
|
||||
|
|
@ -674,7 +674,7 @@ def test_pather_uturn_failed_fallback_is_atomic() -> None:
|
|||
def test_renderpather_rename_to_none_keeps_pending_geometry_without_port() -> None:
|
||||
lib = Library()
|
||||
tool = PathTool(layer='M1', width=1000)
|
||||
rp = RenderPather(lib, tools=tool)
|
||||
rp = Pather(lib, tools=tool, auto_render=False)
|
||||
rp.pattern.ports['A'] = Port((0, 0), rotation=0)
|
||||
|
||||
rp.at('A').straight(5000)
|
||||
|
|
@ -722,7 +722,7 @@ def test_pather_plug_treeview_resolves_once() -> None:
|
|||
def test_pather_failed_plug_does_not_add_break_marker() -> None:
|
||||
lib = Library()
|
||||
tool = PathTool(layer='M1', width=1000)
|
||||
p = Pather(lib, tools=tool)
|
||||
p = Pather(lib, tools=tool, auto_render=False)
|
||||
p.pattern.annotations = {'k': [1]}
|
||||
p.pattern.ports['A'] = Port((0, 0), rotation=0)
|
||||
|
||||
|
|
@ -744,7 +744,7 @@ def test_pather_failed_plug_does_not_add_break_marker() -> None:
|
|||
def test_pather_place_reused_deleted_name_keeps_break_marker() -> None:
|
||||
lib = Library()
|
||||
tool = PathTool(layer='M1', width=1000)
|
||||
p = Pather(lib, tools=tool)
|
||||
p = Pather(lib, tools=tool, auto_render=False)
|
||||
p.pattern.ports['A'] = Port((0, 0), rotation=0)
|
||||
|
||||
p.at('A').straight(5000)
|
||||
|
|
@ -765,7 +765,7 @@ def test_pather_place_reused_deleted_name_keeps_break_marker() -> None:
|
|||
def test_pather_plug_reused_deleted_name_keeps_break_marker() -> None:
|
||||
lib = Library()
|
||||
tool = PathTool(layer='M1', width=1000)
|
||||
p = Pather(lib, tools=tool)
|
||||
p = Pather(lib, tools=tool, auto_render=False)
|
||||
p.pattern.ports['A'] = Port((0, 0), rotation=0)
|
||||
p.pattern.ports['B'] = Port((0, 0), rotation=0)
|
||||
|
||||
|
|
@ -793,7 +793,7 @@ def test_pather_plug_reused_deleted_name_keeps_break_marker() -> None:
|
|||
def test_pather_failed_plugged_does_not_add_break_marker() -> None:
|
||||
lib = Library()
|
||||
tool = PathTool(layer='M1', width=1000)
|
||||
p = Pather(lib, tools=tool)
|
||||
p = Pather(lib, tools=tool, auto_render=False)
|
||||
p.pattern.ports['A'] = Port((0, 0), rotation=0)
|
||||
|
||||
p.at('A').straight(5000)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from typing import cast, TYPE_CHECKING
|
|||
from numpy.testing import assert_allclose
|
||||
from numpy import pi
|
||||
|
||||
from ..builder import RenderPather
|
||||
from ..builder import Pather
|
||||
from ..builder.tools import PathTool
|
||||
from ..library import Library
|
||||
from ..ports import Port
|
||||
|
|
@ -13,15 +13,15 @@ if TYPE_CHECKING:
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def rpather_setup() -> tuple[RenderPather, PathTool, Library]:
|
||||
def rpather_setup() -> tuple[Pather, PathTool, Library]:
|
||||
lib = Library()
|
||||
tool = PathTool(layer=(1, 0), width=2, ptype="wire")
|
||||
rp = RenderPather(lib, tools=tool)
|
||||
rp = Pather(lib, tools=tool, auto_render=False)
|
||||
rp.ports["start"] = Port((0, 0), pi / 2, ptype="wire")
|
||||
return rp, tool, lib
|
||||
|
||||
|
||||
def test_renderpather_basic(rpather_setup: tuple[RenderPather, PathTool, Library]) -> None:
|
||||
def test_renderpather_basic(rpather_setup: tuple[Pather, PathTool, Library]) -> None:
|
||||
rp, tool, lib = rpather_setup
|
||||
# Plan two segments
|
||||
rp.at("start").straight(10).straight(10)
|
||||
|
|
@ -46,7 +46,7 @@ def test_renderpather_basic(rpather_setup: tuple[RenderPather, PathTool, Library
|
|||
assert_allclose(path_shape.vertices, [[0, 0], [0, -10], [0, -20]], atol=1e-10)
|
||||
|
||||
|
||||
def test_renderpather_bend(rpather_setup: tuple[RenderPather, PathTool, Library]) -> None:
|
||||
def test_renderpather_bend(rpather_setup: tuple[Pather, PathTool, Library]) -> None:
|
||||
rp, tool, lib = rpather_setup
|
||||
# Plan straight then bend
|
||||
rp.at("start").straight(10).cw(10)
|
||||
|
|
@ -65,7 +65,7 @@ def test_renderpather_bend(rpather_setup: tuple[RenderPather, PathTool, Library]
|
|||
assert_allclose(path_shape.vertices, [[0, 0], [0, -10], [0, -20], [-1, -20]], atol=1e-10)
|
||||
|
||||
|
||||
def test_renderpather_mirror_preserves_planned_bend_geometry(rpather_setup: tuple[RenderPather, PathTool, Library]) -> None:
|
||||
def test_renderpather_mirror_preserves_planned_bend_geometry(rpather_setup: tuple[Pather, PathTool, Library]) -> None:
|
||||
rp, tool, lib = rpather_setup
|
||||
rp.at("start").straight(10).cw(10)
|
||||
|
||||
|
|
@ -76,7 +76,7 @@ def test_renderpather_mirror_preserves_planned_bend_geometry(rpather_setup: tupl
|
|||
assert_allclose(path_shape.vertices, [[0, 0], [0, 10], [0, 20], [-1, 20]], atol=1e-10)
|
||||
|
||||
|
||||
def test_renderpather_retool(rpather_setup: tuple[RenderPather, PathTool, Library]) -> None:
|
||||
def test_renderpather_retool(rpather_setup: tuple[Pather, PathTool, Library]) -> None:
|
||||
rp, tool1, lib = rpather_setup
|
||||
tool2 = PathTool(layer=(2, 0), width=4, ptype="wire")
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ def test_renderpather_retool(rpather_setup: tuple[RenderPather, PathTool, Librar
|
|||
assert len(rp.pattern.shapes[(2, 0)]) == 1
|
||||
|
||||
|
||||
def test_portpather_translate_only_affects_future_steps(rpather_setup: tuple[RenderPather, PathTool, Library]) -> None:
|
||||
def test_portpather_translate_only_affects_future_steps(rpather_setup: tuple[Pather, PathTool, Library]) -> None:
|
||||
rp, tool, lib = rpather_setup
|
||||
pp = rp.at("start")
|
||||
pp.straight(10)
|
||||
|
|
@ -109,7 +109,7 @@ def test_portpather_translate_only_affects_future_steps(rpather_setup: tuple[Ren
|
|||
def test_renderpather_dead_ports() -> None:
|
||||
lib = Library()
|
||||
tool = PathTool(layer=(1, 0), width=1)
|
||||
rp = RenderPather(lib, ports={"in": Port((0, 0), 0)}, tools=tool)
|
||||
rp = Pather(lib, ports={"in": Port((0, 0), 0)}, tools=tool, auto_render=False)
|
||||
rp.set_dead()
|
||||
|
||||
# Impossible path
|
||||
|
|
@ -126,7 +126,7 @@ def test_renderpather_dead_ports() -> None:
|
|||
assert not rp.pattern.has_shapes()
|
||||
|
||||
|
||||
def test_renderpather_rename_port(rpather_setup: tuple[RenderPather, PathTool, Library]) -> None:
|
||||
def test_renderpather_rename_port(rpather_setup: tuple[Pather, PathTool, Library]) -> None:
|
||||
rp, tool, lib = rpather_setup
|
||||
rp.at("start").straight(10)
|
||||
# Rename port while path is planned
|
||||
|
|
@ -148,7 +148,7 @@ def test_renderpather_rename_port(rpather_setup: tuple[RenderPather, PathTool, L
|
|||
assert_allclose(rp.ports["new_start"].offset, [0, -20], atol=1e-10)
|
||||
|
||||
|
||||
def test_renderpather_drop_keeps_pending_geometry_without_port(rpather_setup: tuple[RenderPather, PathTool, Library]) -> None:
|
||||
def test_renderpather_drop_keeps_pending_geometry_without_port(rpather_setup: tuple[Pather, PathTool, Library]) -> None:
|
||||
rp, tool, lib = rpather_setup
|
||||
rp.at("start").straight(10).drop()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue