"""Returns Component from YAML syntax.
name: myComponent
settings:
length: 3
info:
description: just a demo
polarization: TE
...
instances:
mzi:
component: mzi_phase_shifter
settings:
delta_length: ${settings.length}
length_x: 50
pads:
component: pad_array
settings:
n: 2
port_names:
- e4
placements:
mzi:
x: 0
pads:
y: 200
x: mzi,cc
ports:
o1: mzi,o1
o2: mzi,o2
routes:
electrical:
links:
mzi,etop_e1: pads,e4_0
mzi,etop_e2: pads,e4_1
settings:
layer: [31, 0]
width: 10
radius: 10
"""
from __future__ import annotations
import importlib
import io
import pathlib
import warnings
from collections.abc import Callable
from functools import partial
from typing import IO, Any, Literal
import numpy as np
from omegaconf import DictConfig, OmegaConf
from gdsfactory.add_pins import add_instance_label
from gdsfactory.cell import cell
from gdsfactory.component import (
Component,
ComponentReference,
valid_anchor_point_keywords,
valid_anchor_value_keywords,
valid_anchors,
)
from gdsfactory.typings import Route
valid_placement_keys = [
"x",
"y",
"xmin",
"xmax",
"ymin",
"ymax",
"dx",
"dy",
"rotation",
"mirror",
"port",
]
valid_top_level_keys = [
"name",
"instances",
"placements",
"connections",
"ports",
"routes",
"settings",
"info",
"pdk",
"warnings",
"schema",
"schema_version",
]
valid_route_keys = [
"links",
"settings",
"routing_strategy",
]
# Recognized keys within a YAML route definition
def _get_anchor_point_from_name(
ref: ComponentReference, anchor_name: str
) -> np.ndarray | None:
if anchor_name in valid_anchor_point_keywords:
return getattr(ref.size_info, anchor_name)
elif anchor_name in ref.ports:
return ref.ports[anchor_name].center
else:
return None
def _get_anchor_value_from_name(
ref: ComponentReference, anchor_name: str, return_value: str
) -> float | None:
if anchor_name in valid_anchor_value_keywords:
return getattr(ref.size_info, anchor_name)
anchor_point = _get_anchor_point_from_name(ref, anchor_name)
if anchor_point is None:
return None
if return_value == "x":
return anchor_point[0]
elif return_value == "y":
return anchor_point[1]
else:
raise ValueError("Expected x or y as return_value.")
def _move_ref(
x: str | float,
x_or_y: Literal["x", "y"],
placements_conf,
connections_by_transformed_inst,
instances,
encountered_insts,
all_remaining_insts,
) -> float:
if not isinstance(x, str):
return x
if len(x.split(",")) != 2:
raise ValueError(
f"You can define {x_or_y} as `{x_or_y}: instanceName,portName` got `{x_or_y}: {x!r}`"
)
instance_name_ref, port_name = x.split(",")
if instance_name_ref in all_remaining_insts:
place(
placements_conf,
connections_by_transformed_inst,
instances,
encountered_insts,
instance_name_ref,
all_remaining_insts,
)
if instance_name_ref not in instances:
raise ValueError(
f"{instance_name_ref!r} not in {list(instances.keys())}."
f" You can define {x_or_y} as `{x_or_y}: instanceName,portName`, got {x_or_y}: {x!r}"
)
if (
port_name not in instances[instance_name_ref].ports
and port_name not in valid_anchors
):
ports = list(instances[instance_name_ref].ports.keys())
raise ValueError(
f"port = {port_name!r} can be a port_name in {ports}, "
f"an anchor {valid_anchors} for {instance_name_ref!r}, "
f"or `{x_or_y}: instanceName,portName`, got `{x_or_y}: {x!r}`"
)
return _get_anchor_value_from_name(instances[instance_name_ref], port_name, x_or_y)
def place(
placements_conf: dict[str, dict[str, int | float | str]],
connections_by_transformed_inst: dict[str, dict[str, str]],
instances: dict[str, ComponentReference],
encountered_insts: list[str],
instance_name: str | None = None,
all_remaining_insts: list[str] | None = None,
) -> None:
"""Place instance_name based on placements_conf config.
Args:
placements_conf: Dict of instance_name to placement (x, y, rotation ...).
connections_by_transformed_inst: Dict of connection attributes.
keyed by the name of the instance which should be transformed.
instances: Dict of references.
encountered_insts: list of encountered_instances.
instance_name: instance_name to place.
all_remaining_insts: list of all the remaining instances to place
instances pop from this instance as they are placed.
"""
if not all_remaining_insts:
return
if instance_name is None:
instance_name = all_remaining_insts.pop(0)
else:
all_remaining_insts.remove(instance_name)
if instance_name in encountered_insts:
encountered_insts.append(instance_name)
loop_str = " -> ".join(encountered_insts)
raise ValueError(
f"circular reference in placement for {instance_name}! Loop: {loop_str}"
)
encountered_insts.append(instance_name)
if instance_name not in instances:
raise ValueError(f"{instance_name!r} not in {list(instances.keys())}")
ref = instances[instance_name]
if instance_name in placements_conf:
placement_settings = placements_conf[instance_name] or {}
if not isinstance(placement_settings, dict):
raise ValueError(
f"Invalid placement {placement_settings} from {valid_placement_keys}"
)
for k in placement_settings.keys():
if k not in valid_placement_keys:
raise ValueError(f"Invalid placement {k} from {valid_placement_keys}")
x = placement_settings.get("x")
xmin = placement_settings.get("xmin")
xmax = placement_settings.get("xmax")
y = placement_settings.get("y")
ymin = placement_settings.get("ymin")
ymax = placement_settings.get("ymax")
dx = placement_settings.get("dx")
dy = placement_settings.get("dy")
port = placement_settings.get("port")
rotation = placement_settings.get("rotation")
mirror = placement_settings.get("mirror")
if mirror:
if mirror is True and port:
ref.mirror_x(x0=_get_anchor_value_from_name(ref, port, "x"))
elif mirror is True:
if x is not None:
ref.mirror_x(x0=_get_anchor_value_from_name(ref, x, "x"))
else:
ref.mirror_x()
elif mirror is False:
pass
elif isinstance(mirror, str):
ref.mirror_x(port_name=mirror)
elif isinstance(mirror, int | float):
ref.mirror_x(x0=mirror)
else:
raise ValueError(
f"{mirror!r} can only be a port name {ref.ports.keys()}, "
"x value or True/False"
)
if port:
a = _get_anchor_point_from_name(ref, port)
if a is None:
raise ValueError(
f"Port {port!r} is neither a valid port on {ref.parent.name!r}"
" nor a recognized anchor keyword.\n"
"Valid ports: \n"
f"{list(ref.ports.keys())}. \n"
"Valid keywords: \n"
f"{valid_anchor_point_keywords}",
)
ref.x -= a[0]
ref.y -= a[1]
if x is not None:
ref.x += _move_ref(
x,
x_or_y="x",
placements_conf=placements_conf,
connections_by_transformed_inst=connections_by_transformed_inst,
instances=instances,
encountered_insts=encountered_insts,
all_remaining_insts=all_remaining_insts,
)
# print(instance_name, x, xmin, xmax, y, ymin, ymax)
# print(ymin, y or ymin or ymax)
if y is not None:
ref.y += _move_ref(
y,
x_or_y="y",
placements_conf=placements_conf,
connections_by_transformed_inst=connections_by_transformed_inst,
instances=instances,
encountered_insts=encountered_insts,
all_remaining_insts=all_remaining_insts,
)
if rotation:
if port:
ref.rotate(rotation, center=_get_anchor_point_from_name(ref, port))
else:
x, y = ref.origin
ref.rotate(rotation, center=(x, y))
# ref.rotate(rotation, center=(ref.x, ref.y))
if ymin is not None and ymax is not None:
raise ValueError("You cannot set ymin and ymax")
elif ymax is not None:
ref.ymax = _move_ref(
ymax,
x_or_y="y",
placements_conf=placements_conf,
connections_by_transformed_inst=connections_by_transformed_inst,
instances=instances,
encountered_insts=encountered_insts,
all_remaining_insts=all_remaining_insts,
)
elif ymin is not None:
ref.ymin = _move_ref(
ymin,
x_or_y="y",
placements_conf=placements_conf,
connections_by_transformed_inst=connections_by_transformed_inst,
instances=instances,
encountered_insts=encountered_insts,
all_remaining_insts=all_remaining_insts,
)
if xmin is not None and xmax is not None:
raise ValueError("You cannot set xmin and xmax")
elif xmin is not None:
ref.xmin = _move_ref(
xmin,
x_or_y="x",
placements_conf=placements_conf,
connections_by_transformed_inst=connections_by_transformed_inst,
instances=instances,
encountered_insts=encountered_insts,
all_remaining_insts=all_remaining_insts,
)
elif xmax is not None:
ref.xmax = _move_ref(
xmax,
x_or_y="x",
placements_conf=placements_conf,
connections_by_transformed_inst=connections_by_transformed_inst,
instances=instances,
encountered_insts=encountered_insts,
all_remaining_insts=all_remaining_insts,
)
if dx:
ref.x += dx
if dy:
ref.y += dy
if instance_name in connections_by_transformed_inst:
conn_info = connections_by_transformed_inst[instance_name]
instance_dst_name = conn_info["instance_dst_name"]
if instance_dst_name in all_remaining_insts:
place(
placements_conf,
connections_by_transformed_inst,
instances,
encountered_insts,
instance_dst_name,
all_remaining_insts,
)
make_connection(instances=instances, **conn_info)
# placements_conf.pop(instance_name)
def transform_connections_dict(connections_conf: dict[str, str]) -> dict[str, dict]:
"""Returns Dict with source_instance_name key and connection properties."""
if not connections_conf:
return {}
attrs_by_src_inst = {}
for port_src_string, port_dst_string in connections_conf.items():
instance_src_name, port_src_name = port_src_string.split(",")
instance_dst_name, port_dst_name = port_dst_string.split(",")
attrs_by_src_inst[instance_src_name] = {
"instance_src_name": instance_src_name,
"port_src_name": port_src_name,
"instance_dst_name": instance_dst_name,
"port_dst_name": port_dst_name,
}
return attrs_by_src_inst
def make_connection(
instance_src_name: str,
port_src_name: str,
instance_dst_name: str,
port_dst_name: str,
instances: dict[str, ComponentReference],
) -> None:
"""Connect instance_src_name,port to instance_dst_name,port.
Args:
instance_src_name: source instance name.
port_src_name: from instance_src_name.
instance_dst_name: destination instance name.
port_dst_name: from instance_dst_name.
instances: dict of instances.
"""
instance_src_name = instance_src_name.strip()
instance_dst_name = instance_dst_name.strip()
port_src_name = port_src_name.strip()
port_dst_name = port_dst_name.strip()
if instance_src_name not in instances:
raise ValueError(f"{instance_src_name!r} not in {list(instances.keys())}")
if instance_dst_name not in instances:
raise ValueError(f"{instance_dst_name!r} not in {list(instances.keys())}")
instance_src = instances[instance_src_name]
instance_dst = instances[instance_dst_name]
if port_src_name not in instance_src.ports:
raise ValueError(
f"{port_src_name} not in {list(instance_src.ports.keys())} for"
f" {instance_src_name!r} "
)
if port_dst_name not in instance_dst.ports:
raise ValueError(
f"{port_dst_name!r} not in {list(instance_dst.ports.keys())} for"
f" {instance_dst_name!r}"
)
port_dst = instance_dst.ports[port_dst_name]
instance_src.connect(port=port_src_name, destination=port_dst)
sample_mmis = """
name: sample_mmis
info:
polarization: te
wavelength: 1.55
description: just a demo on adding metadata
instances:
mmi_long:
component: mmi1x2
settings:
width_mmi: 4.5
length_mmi: 10
mmi_short:
component: mmi1x2
settings:
width_mmi: 4.5
length_mmi: 5
placements:
mmi_long:
rotation: 180
x: 100
y: 100
routes:
route_name1:
links:
mmi_short,o2: mmi_long,o1
ports:
o1: mmi_short,o1
o2: mmi_long,o2
o3: mmi_long,o3
"""
def cell_from_yaml(
yaml_str: str | pathlib.Path | IO[Any] | dict[str, Any] | DictConfig,
routing_strategy: dict[str, Callable] | None = None,
label_instance_function: Callable = add_instance_label,
**kwargs,
) -> Callable:
"""Returns Component factory from YAML string or file.
YAML includes instances, placements, routes, ports and connections.
Args:
yaml: YAML string or file.
routing_strategy: for each route.
label_instance_function: to label each instance.
name: Optional name.
kwargs: function settings for creating YAML PCells.
.. code::
valid variables:
name: Optional Component name
settings: Optional variables
pdk: overrides
info: Optional component info
description: just a demo
polarization: TE
...
instances:
name:
component: (ComponentSpec)
settings (Optional)
length: 10
...
placements:
x: float, str | None str can be instanceName,portName
y: float, str | None
rotation: float | None
mirror: bool, float | None float is x mirror axis
port: str | None port anchor
connections (Optional): between instances
ports (Optional): ports to expose
routes (Optional): bundles of routes
routeName:
library: optical
links:
instance1,port1: instance2,port2
.. code::
settings:
length_mmi: 5
instances:
mmi_bot:
component: mmi1x2
settings:
width_mmi: 4.5
length_mmi: 10
mmi_top:
component: mmi1x2
settings:
width_mmi: 4.5
length_mmi: ${settings.length_mmi}
placements:
mmi_top:
port: o1
x: 0
y: 0
mmi_bot:
port: o1
x: mmi_top,o2
y: mmi_top,o2
dx: 30
dy: -30
routes:
optical:
library: optical
links:
mmi_top,o3: mmi_bot,o1
"""
return partial(
from_yaml,
yaml_str=yaml_str,
routing_strategy=routing_strategy,
label_instance_function=label_instance_function,
**kwargs,
)
[docs]
def from_yaml(
yaml_str: str | pathlib.Path | IO[Any] | dict[str, Any] | DictConfig,
routing_strategy: dict[str, Callable] | None = None,
label_instance_function: Callable = add_instance_label,
name: str | None = None,
prefix: str | None = None,
validate: bool = False,
**kwargs,
) -> Component:
"""Returns Component from YAML string or file.
YAML includes instances, placements, routes, ports and connections.
Args:
yaml: YAML string or file.
routing_strategy: for each route.
label_instance_function: to label each instance.
name: Optional name.
prefix: name prefix.
validate: validate component.
kwargs: function settings for creating YAML PCells.
.. code::
valid variables:
name: Optional Component name
settings: Optional variables
pdk: overrides
info: Optional component info
description: just a demo
polarization: TE
...
instances:
name:
component: (ComponentSpec)
settings (Optional)
length: 10
...
placements:
x: float, str | None str can be instanceName,portName
y: float, str | None
rotation: float | None
mirror: bool, float | None float is x mirror axis
port: str | None port anchor
connections (Optional): between instances
ports (Optional): ports to expose
routes (Optional): bundles of routes
routeName:
library: optical
links:
instance1,port1: instance2,port2
.. code::
settings:
length_mmi: 5
instances:
mmi_bot:
component: mmi1x2
settings:
width_mmi: 4.5
length_mmi: 10
mmi_top:
component: mmi1x2
settings:
width_mmi: 4.5
length_mmi: ${settings.length_mmi}
placements:
mmi_top:
port: o1
x: 0
y: 0
mmi_bot:
port: o1
x: mmi_top,o2
y: mmi_top,o2
dx: 30
dy: -30
routes:
optical:
library: optical
links:
mmi_top,o3: mmi_bot,o1
"""
from gdsfactory.pdk import get_routing_strategies
if routing_strategy is None:
routing_strategy = get_routing_strategies()
if isinstance(yaml_str, str | pathlib.Path | IO):
yaml_str = (
io.StringIO(yaml_str)
if isinstance(yaml_str, str) and "\n" in yaml_str
else yaml_str
)
conf = OmegaConf.load(
yaml_str
) # nicer loader than conf = yaml.safe_load(yaml_str)
else:
conf = OmegaConf.create(yaml_str)
for key in conf.keys():
if key not in valid_top_level_keys:
raise ValueError(f"{key!r} not in {list(valid_top_level_keys)}")
settings = conf.get("settings", {})
mode = kwargs.pop("mode") if "mode" in kwargs else "layout"
for key, value in kwargs.items():
if key not in settings:
raise ValueError(f"{key!r} not in {settings.keys()}")
else:
conf["settings"][key] = value
c = _from_yaml(
conf=OmegaConf.to_container(conf, resolve=True),
routing_strategy=routing_strategy,
label_instance_function=label_instance_function,
mode=mode,
prefix=prefix or conf.get("name", "Unnamed"),
name=name,
validate=validate,
)
return c
@cell
def _from_yaml(
conf,
routing_strategy: dict[str, Callable],
label_instance_function: Callable = add_instance_label,
mode: str = "layout",
validate: bool = False,
) -> Component:
"""Returns component from YAML decorated with cell for caching and autonaming.
Args:
conf: dict.
routing_strategy: for each route.
label_instance_function: to label each instance.
mode: layout or schematic.
validate: validate component.
"""
from gdsfactory.generic_tech import get_generic_pdk
from gdsfactory.pdk import get_active_pdk
GENERIC = get_generic_pdk()
c = Component()
instances = {}
routes = {}
placements_conf = conf.get("placements")
routes_conf = conf.get("routes")
ports_conf = conf.get("ports")
connections_conf = conf.get("connections")
instances_dict = conf["instances"]
pdk = conf.get("pdk")
c.info.update(conf.get("info", {}))
if pdk and pdk == "generic":
GENERIC.activate()
elif pdk:
module = importlib.import_module(pdk)
pdk = module.PDK
if pdk is None:
raise ValueError(f"'from {pdk} import PDK' failed")
pdk.activate()
pdk = get_active_pdk()
if mode == "layout":
if validate:
component_getter = partial(pdk.get_component, validate=True)
else:
component_getter = pdk.get_component
elif mode == "schematic":
component_getter = pdk.get_symbol
else:
raise ValueError(
f"{mode} is not a recognized mode. Please choose 'layout' or 'schematic'"
)
for instance_name in instances_dict:
instance_conf = instances_dict[instance_name]
component = instance_conf["component"]
settings = instance_conf.get("settings", {})
component_spec = {"component": component, "settings": settings}
component = component_getter(component_spec)
ref = c.add_ref(component, alias=instance_name)
instances[instance_name] = ref
placements_conf = dict() if placements_conf is None else placements_conf
connections_by_transformed_inst = transform_connections_dict(connections_conf)
components_to_place = set(placements_conf.keys())
components_with_placement_conflicts = components_to_place.intersection(
connections_by_transformed_inst.keys()
)
for instance_name in components_with_placement_conflicts:
placement_settings = placements_conf[instance_name]
if "x" in placement_settings or "y" in placement_settings:
warnings.warn(
f"YAML defined: ({', '.join(components_with_placement_conflicts)}) "
"with both connection and placement. Please use one or the other.",
)
all_remaining_insts = list(
set(placements_conf.keys()).union(set(connections_by_transformed_inst.keys()))
)
while all_remaining_insts:
place(
placements_conf=placements_conf,
connections_by_transformed_inst=connections_by_transformed_inst,
instances=instances,
encountered_insts=[],
all_remaining_insts=all_remaining_insts,
)
for instance_name in instances_dict:
label_instance_function(
component=c, instance_name=instance_name, reference=instances[instance_name]
)
if routes_conf:
for route_alias in routes_conf:
route_names = []
ports1 = []
ports2 = []
routes_dict = routes_conf[route_alias]
for key in routes_dict.keys():
if key not in valid_route_keys:
raise ValueError(
f"{route_alias!r} key={key!r} not in {valid_route_keys}"
)
settings = routes_dict.pop("settings", {})
routing_strategy_name = routes_dict.pop("routing_strategy", "get_bundle")
if routing_strategy_name not in routing_strategy:
routing_strategies = list(routing_strategy.keys())
raise ValueError(
f"{routing_strategy_name!r} is an invalid routing_strategy "
f"{routing_strategies}"
)
if "links" not in routes_dict:
raise ValueError(
f"You need to define links for the {route_alias!r} route"
)
links_dict = routes_dict["links"]
for port_src_string, port_dst_string in links_dict.items():
if ":" in port_src_string:
src, src0, src1 = (s.strip() for s in port_src_string.split(":"))
dst, dst0, dst1 = (s.strip() for s in port_dst_string.split(":"))
instance_src_name, port_src_name = (
s.strip() for s in src.split(",")
)
instance_dst_name, port_dst_name = (
s.strip() for s in dst.split(",")
)
src0 = int(src0)
src1 = int(src1)
dst0 = int(dst0)
dst1 = int(dst1)
if src1 > src0:
ports1names = [
f"{port_src_name}{i}" for i in range(src0, src1 + 1)
]
else:
ports1names = [
f"{port_src_name}{i}" for i in range(src0, src1 - 1, -1)
]
if dst1 > dst0:
ports2names = [
f"{port_dst_name}{i}" for i in range(dst0, dst1 + 1)
]
else:
ports2names = [
f"{port_dst_name}{i}" for i in range(dst0, dst1 - 1, -1)
]
if len(ports1names) != len(ports2names):
raise ValueError(f"{ports1names} different from {ports2names}")
route_names += [
f"{instance_src_name},{i}:{instance_dst_name},{j}"
for i, j in zip(ports1names, ports2names)
]
instance_src = instances[instance_src_name]
instance_dst = instances[instance_dst_name]
for port_src_name in ports1names:
if port_src_name not in instance_src.ports:
raise ValueError(
f"{port_src_name!r} not in {list(instance_src.ports.keys())}"
f"for {instance_src_name!r} "
)
ports1.append(instance_src.ports[port_src_name])
for port_dst_name in ports2names:
if port_dst_name not in instance_dst.ports:
raise ValueError(
f"{port_dst_name!r} not in {list(instance_dst.ports.keys())}"
f"for {instance_dst_name!r}"
)
ports2.append(instance_dst.ports[port_dst_name])
else:
instance_src_name, port_src_name = port_src_string.split(",")
instance_dst_name, port_dst_name = port_dst_string.split(",")
instance_src_name = instance_src_name.strip()
instance_dst_name = instance_dst_name.strip()
port_src_name = port_src_name.strip()
port_dst_name = port_dst_name.strip()
if instance_src_name not in instances:
raise ValueError(
f"{instance_src_name!r} not in {list(instances.keys())}"
)
if instance_dst_name not in instances:
raise ValueError(
f"{instance_dst_name!r} not in {list(instances.keys())}"
)
instance_src = instances[instance_src_name]
instance_dst = instances[instance_dst_name]
if port_src_name not in instance_src.ports:
raise ValueError(
f"{port_src_name!r} not in {list(instance_src.ports.keys())} for"
f" {instance_src_name!r} "
)
if port_dst_name not in instance_dst.ports:
raise ValueError(
f"{port_dst_name!r} not in {list(instance_dst.ports.keys())} for"
f" {instance_dst_name!r}"
)
ports1.append(instance_src.ports[port_src_name])
ports2.append(instance_dst.ports[port_dst_name])
route_name = f"{port_src_string}:{port_dst_string}"
route_names.append(route_name)
routing_function = routing_strategy[routing_strategy_name]
route_or_route_list = routing_function(
ports1=ports1,
ports2=ports2,
**settings,
)
# FIXME, be more consistent
if isinstance(route_or_route_list, list):
for route_name, route_dict in zip(route_names, route_or_route_list):
c.add(route_dict.references)
routes[route_name] = route_dict.length
elif isinstance(route_or_route_list, Route):
c.add(route_or_route_list.references)
routes[route_name] = route_or_route_list.length
else:
raise ValueError(f"{route_or_route_list} needs to be a Route or a list")
if ports_conf:
if not hasattr(ports_conf, "items"):
raise ValueError(f"{ports_conf} needs to be a dict")
for port_name, instance_comma_port in ports_conf.items():
if "," in instance_comma_port:
instance_name, instance_port_name = instance_comma_port.split(",")
instance_name = instance_name.strip()
instance_port_name = instance_port_name.strip()
if instance_name not in instances:
raise ValueError(
f"{instance_name!r} not in {list(instances.keys())}"
)
instance = instances[instance_name]
if instance_port_name not in instance.ports:
raise ValueError(
f"{instance_port_name!r} not in {list(instance.ports.keys())} for"
f" {instance_name!r} "
)
c.add_port(port_name, port=instance.ports[instance_port_name])
else:
c.add_port(**instance_comma_port)
c.routes = routes
return c
sample_pdk = """
pdk: ubcpdk
info:
polarization: te
wavelength: 1.55
description: mzi for ubcpdk
instances:
yr:
component: y_splitter
yl:
component: y_splitter
placements:
yr:
rotation: 180
x: 100
y: 100
routes:
route_top:
links:
yl,opt2: yr,opt3
route_bot:
links:
yl,opt3: yr,opt2
routing_strategy: get_bundle_from_steps
ports:
o1: yl,opt1
o2: yr,opt2
o3: yr,opt3
"""
sample_pdk_mzi = """
name: mzi
pdk: ubcpdk
info:
polarization: te
wavelength: 1.55
description: mzi for ubcpdk
instances:
yr:
component: y_splitter
yl:
component: y_splitter
placements:
yr:
rotation: 180
x: 100
y: 0
routes:
route_top:
links:
yl,opt2: yr,opt3
route_bot:
links:
yl,opt3: yr,opt2
routing_strategy: get_bundle_from_steps
settings:
steps: [dx: 30, dy: -40, dx: 20]
ports:
o1: yl,opt1
o2: yr,opt2
o3: yr,opt3
"""
sample_pdk_mzi_settings = """
name: mzi
pdk: ubcpdk
settings:
dy: -70
info:
polarization: te
wavelength: 1.55
description: mzi for ubcpdk
instances:
yr:
component: ebeam_y_1550
yl:
component: ebeam_y_1550
placements:
yr:
rotation: 180
x: 100
y: 0
routes:
route_top:
links:
yl,opt2: yr,opt3
settings:
cross_section: strip
route_bot:
links:
yl,opt3: yr,opt2
routing_strategy: get_bundle_from_steps
settings:
steps: [dx: 30, dy: '${settings.dy}', dx: 20]
cross_section: strip
ports:
o1: yl,opt1
o2: yr,opt1
"""
sample_pdk_mzi_lattice = """
name: lattice_filter
pdk: ubcpdk
instances:
mzi1:
component: mzi.icyaml
mzi2:
component: mzi.icyaml
"""
sample_yaml_xmin = """
name: mask_compact
instances:
mmi1x2_sweep_pack:
component: pack_doe
settings:
component: mmi1x2
length_mmi: [2, 100]
width_mmi: [4, 10]
pack:
do_permutations: True
spacing: 100
mzi_sweep:
component: pack_doe
settings:
component: mzi
delta_length: [10, 100]
pack:
do_permutations: True
spacing: 100
placements:
mmi1x2_sweep_pack:
xmin: -10
mzi_sweep:
xmin: mmi1x2_sweep_pack,east
"""
sample_doe = """
name: mask_compact
pdk: ubcpdk
instances:
rings:
component: pack_doe
settings:
doe: ring_single
settings:
radius: [30, 50, 20, 40]
length_x: [1, 2, 3]
do_permutations: True
function:
function: add_fiber_array
settings:
fanout_length: 200
mzis:
component: pack_doe_grid
settings:
doe: mzi
settings:
delta_length: [10, 100]
do_permutations: True
spacing: [10, 10]
function: add_fiber_array
placements:
rings:
xmin: 50
mzis:
xmin: rings,east
"""
sample_add_gratings = """
name: sample_add_gratings
pdk: ubcpdk
instances:
ring_te:
component:
component: add_fiber_array
settings:
component: ring_single
"""
sample_add_gratings_doe = """
name: sample_add_gratings_doe
pdk: ubcpdk
instances:
ring_te:
component:
component: pack_doe
settings:
component: add_fiber_array
settings:
component: ring_single
"""
sample_rotation_hacky = """
name: sample_rotation
instances:
r1:
component: rectangle
settings:
size: [4, 2]
r2:
component: rectangle
settings:
size: [2, 4]
placements:
r1:
xmin: 0
ymin: 0
r2:
rotation: 90
xmin: r1,west
ymin: 0
"""
sample_rotation = """
name: sample_rotation
instances:
r1:
component: rectangle
settings:
size: [4, 2]
r2:
component: rectangle
settings:
size: [2, 4]
placements:
r1:
xmin: 0
ymin: 0
r2:
rotation: -90
xmin: r1,east
ymin: 0
"""
sample2 = """
name: sample_different_factory2
instances:
tl:
component: pad
tr:
component: pad
mzi:
component: mzi_phase_shifter
placements:
mzi:
ymax: tl,south
dy: -100
tl:
x: mzi,west
y: mzi,north
dy: 100
tr:
x: mzi,west
dx: 200
y: mzi,north
dy: 100
routes:
electrical1:
routing_strategy: get_bundle
settings:
separation: 20
layer: [31, 0]
width: 10
links:
mzi,e2: tr,e1
electrical2:
routing_strategy: get_bundle
settings:
separation: 20
layer: [31, 0]
width: 10
links:
mzi,e1: tl,e1
"""
sample_mirror = """
name: sample_mirror
instances:
mmi1:
component: mmi1x2
mmi2:
component: mmi1x2
placements:
mmi1:
xmax: 0
mmi2:
xmin: mmi1,east
mirror: True
"""
sample_doe_function = """
name: mask_compact
instances:
rings:
component: pack_doe
settings:
doe: ring_single
settings:
radius: [30, 50, 20, 40]
length_x: [1, 2, 3]
do_permutations: True
function:
function: add_fiber_array
settings:
fanout_length: 200
mzis:
component: pack_doe_grid
settings:
doe: mzi
settings:
delta_length: [10, 100]
do_permutations: True
spacing: [10, 10]
function: add_fiber_array
placements:
rings:
xmin: 50
mzis:
xmin: rings,east
"""
if __name__ == "__main__":
import gdsfactory as gf
# c = from_yaml(sample_doe_function)
c = from_yaml(sample_mmis)
n = c.get_netlist()
gf.clear_cache()
yaml_str = OmegaConf.to_yaml(n, sort_keys=True)
c2 = from_yaml(yaml_str)
n2 = c2.get_netlist()
c2.show()