def add_keepout( component: Component, target_layers: Layers, keepout_layers: Layers, margin: float = 2.0, ) -> Component: """Adds keepout after Looking up all polygons in a cell. You can also use add_padding Args: component target_layers: list of layers to read keepout_layers: list of layers to add keepout margin: offset from tareget to keepout_layers """ c = Component(f"{component.name}_ko") c << component for layer in target_layers: polygons = component.get_polygons(by_spec=layer) if polygons: for ko_layer in keepout_layers: ko_layer = _parse_layer(ko_layer) polygon_keepout = [ polygon_grow(polygon, margin) for polygon in polygons ] c.add_polygon(polygon_keepout, ko_layer) return c
def get_input_label_electrical(port, index=0, component_name=None, layer_label=LAYER.LABEL): """ Generate a label to test component info for a given grating coupler. This is the label used by T&M to extract grating coupler coordinates and match it to the component. """ if component_name: name = component_name elif type(port.parent) == pp.Component: name = port.parent.name else: name = port.parent.ref_cell.name text = "elec_{}_({})_{}".format(index, name, port.name) gds_layer_label, gds_datatype_label = pd._parse_layer(layer_label) label = pd.Label( text=text, position=port.midpoint, anchor="o", layer=gds_layer_label, texttype=gds_datatype_label, ) return label
def get_input_labels( io_gratings, ordered_ports, component_name, layer_label=layer_label, gc_port_name=gc_port_name, port_index=1, ): """ get labels for all component ports """ if port_index == -1: return get_input_labels_all( io_gratings=io_gratings, ordered_ports=ordered_ports, component_name=component_name, gc_port_name=gc_port_name, port_index=port_index, ) gc = io_gratings[port_index] port = ordered_ports[1] text = get_optical_text(port=port, gc=gc, gc_index=port_index, component_name=component_name) print(text) layer, texttype = pd._parse_layer(layer_label) label = pd.Label( text=text, position=gc.ports[gc_port_name].midpoint, anchor="o", layer=layer, texttype=texttype, ) return [label]
def get_input_labels( io_gratings: List[ComponentReference], ordered_ports: List[Port], component_name: str, layer_label: Tuple[int, int] = LAYER.LABEL, gc_port_name: str = "W0", port_index: int = 1, ) -> List[Label]: """Return labels (elements list) for all component ports.""" if port_index == -1: return get_input_labels_all( io_gratings=io_gratings, ordered_ports=ordered_ports, component_name=component_name, layer_label=layer_label, gc_port_name=gc_port_name, ) gc = io_gratings[port_index] port = ordered_ports[1] text = get_optical_text(port=port, gc=gc, gc_index=port_index, component_name=component_name) layer, texttype = pd._parse_layer(layer_label) label = pd.Label( text=text, position=gc.ports[gc_port_name].midpoint, anchor="o", layer=layer, texttype=texttype, ) return [label]
def get_input_label( port: Port, gc: ComponentReference, gc_index: Optional[int] = None, gc_port_name: str = "W0", layer_label: ListConfig = pp.LAYER.LABEL, component_name: Optional[str] = None, ) -> Label: """ Generate a label with component info for a given grating coupler. This is the label used by T&M to extract grating coupler coordinates and match it to the component. """ text = get_optical_text(port=port, gc=gc, gc_index=gc_index, component_name=component_name) if gc_port_name is None: gc_port_name = list(gc.ports.values())[0].name layer, texttype = pd._parse_layer(layer_label) label = pd.Label( text=text, position=gc.ports[gc_port_name].midpoint, anchor="o", layer=layer, texttype=texttype, ) return label
def add_keepout(c, target_layers, keepout_layers, margin=2.0): """ Lookup all polygons in this cell """ all_cells = list(c.get_dependencies(True)) + [c] for _c in all_cells: for _layer in target_layers: polys_by_layer = _c.get_polygons(by_spec=True) layer = _parse_layer(_layer) for ko_layer in keepout_layers: ko_layer = _parse_layer(ko_layer) polys = polys_by_layer[ layer] if layer in polys_by_layer else [] if not polys: continue ko_polys_pts = [polygon_grow(poly, margin) for poly in polys] _c.add_polygon(ko_polys_pts, ko_layer)
def extract( self, layers: Union[List[Tuple[int, int]], Tuple[int, int]] = (), ) -> Device: """Extract polygons from a Component. adapted from phidl.geometry. """ from gdsfactory.name import clean_value component = Component(f"{self.name}_{clean_value(layers)}") if type(layers) not in (list, tuple): raise ValueError("layers needs to be a list or tuple") poly_dict = self.get_polygons(by_spec=True) parsed_layer_list = [_parse_layer(layer) for layer in layers] for layer, polys in poly_dict.items(): if _parse_layer(layer) in parsed_layer_list: component.add_polygon(polys, layer=layer) return component
def remove_layers( self, layers: Union[List[Tuple[int, int]], Tuple[int, int]] = (), include_labels: bool = True, invert_selection: bool = False, recursive: bool = True, ) -> Device: """Remove a list of layers.""" layers = [_parse_layer(layer) for layer in layers] all_D = list(self.get_dependencies(recursive)) all_D += [self] for D in all_D: for polygonset in D.polygons: polygon_layers = zip(polygonset.layers, polygonset.datatypes) polygons_to_keep = [(pl in layers) for pl in polygon_layers] if not invert_selection: polygons_to_keep = [(not p) for p in polygons_to_keep] polygonset.polygons = [ p for p, keep in zip(polygonset.polygons, polygons_to_keep) if keep ] polygonset.layers = [ p for p, keep in zip(polygonset.layers, polygons_to_keep) if keep ] polygonset.datatypes = [ p for p, keep in zip(polygonset.datatypes, polygons_to_keep) if keep ] if include_labels: new_labels = [] for label in D.labels: original_layer = (label.layer, label.texttype) original_layer = _parse_layer(original_layer) if invert_selection: keep_layer = original_layer in layers else: keep_layer = original_layer not in layers if keep_layer: new_labels += [label] D.labels = new_labels return self
def remove_layers(self, layers=(), include_labels=True, invert_selection=False, recursive=True): """ remove a list of layers """ layers = [_parse_layer(l) for l in layers] all_D = list(self.get_dependencies(recursive)) all_D += [self] for D in all_D: for polygonset in D.polygons: polygon_layers = zip(polygonset.layers, polygonset.datatypes) polygons_to_keep = [(pl in layers) for pl in polygon_layers] if invert_selection == False: polygons_to_keep = [(not p) for p in polygons_to_keep] polygonset.polygons = [ p for p, keep in zip(polygonset.polygons, polygons_to_keep) if keep ] polygonset.layers = [ p for p, keep in zip(polygonset.layers, polygons_to_keep) if keep ] polygonset.datatypes = [ p for p, keep in zip(polygonset.datatypes, polygons_to_keep) if keep ] if include_labels == True: new_labels = [] for l in D.labels: original_layer = (l.layer, l.texttype) original_layer = _parse_layer(original_layer) if invert_selection: keep_layer = original_layer in layers else: keep_layer = original_layer not in layers if keep_layer: new_labels += [l] D.labels = new_labels return self
def add_label(component, text, position=(0, 0), layer=pp.LAYER.LABEL): gds_layer_label, gds_datatype_label = pd._parse_layer(layer) label = pd.Label( text=text, position=position, anchor="o", layer=gds_layer_label, texttype=gds_datatype_label, ) component.add(label) return component
def label(text, position=(0, 0), layer=66): gds_layer_label, gds_datatype_label = pd._parse_layer(layer) label_ref = pd.Label( text=text, position=position, anchor="o", layer=gds_layer_label, texttype=gds_datatype_label, ) return label_ref
def write_component( component: Component, gdspath: Optional[PosixPath] = None, path_library: PosixPath = CONFIG["gds_directory"], precision: float = 1e-9, settings: None = None, with_settings_label: bool = conf.tech.with_settings_label, ) -> str: """write component GDS and metadata: - gds - ports - properties Args: component: gdspath: path_library precision: to save GDS points settings: dict of settings """ gdspath = gdspath or path_library / (component.name + ".gds") gdspath = pathlib.Path(gdspath) ports_path = gdspath.with_suffix(".ports") json_path = gdspath.with_suffix(".json") """ write GDS """ gdspath = write_gds( component=component, gdspath=str(gdspath), precision=precision, with_settings_label=with_settings_label, ) """ write .ports in CSV""" if len(component.ports) > 0: with open(ports_path, "w") as fw: for _, port in component.ports.items(): layer, texttype = pd._parse_layer(port.layer) fw.write("{}, {:.3f}, {:.3f}, {}, {:.3f}, {}, {}\n".format( port.name, port.x, port.y, int(port.orientation), port.width, layer, texttype, )) """ write JSON """ with open(json_path, "w+") as fw: fw.write(json.dumps(component.get_json(), indent=2)) return gdspath
def label( text: str = "abc", position: Tuple[float, float] = (0.0, 0.0), layer: Tuple[int, int] = pp.LAYER.TEXT, ) -> Label: gds_layer_label, gds_datatype_label = pd._parse_layer(layer) label_ref = pd.Label( text=text, position=position, anchor="o", layer=gds_layer_label, texttype=gds_datatype_label, ) return label_ref
def write_component( component: Component, gdspath: Optional[PosixPath] = None, gdsdir: PosixPath = tmp, precision: float = 1e-9, ) -> PosixPath: """write component GDS and metadata: - gds - ports - properties Args: component: gdspath: path_library precision: to save GDS points """ gdspath = gdspath or gdsdir / (component.name + ".gds") gdspath = pathlib.Path(gdspath) ports_path = gdspath.with_suffix(".ports") json_path = gdspath.with_suffix(".json") gdspath = write_gds( component=component, gdspath=str(gdspath), precision=precision, ) # component.ports CSV if len(component.ports) > 0: with open(ports_path, "w") as fw: for port in component.ports.values(): layer, purpose = pd._parse_layer(port.layer) fw.write( f"{port.name}, {port.x:.3f}, {port.y:.3f}, {int(port.orientation)}, {port.width:.3f}, {layer}, {purpose}\n" ) # component.json metadata dict with open(json_path, "w+") as fw: fw.write(json.dumps(component.get_json(), indent=2)) return gdspath
def get_input_label_electrical( port: Port, gc_index: int = 0, component_name: Optional[str] = None, layer_label: Layer = pp.LAYER.LABEL, gc: Optional[ComponentReference] = None, ): """ Generate a label to test component info for a given electrical port. This is the label used by T&M to extract grating coupler coordinates and match it to the component. Args: port: gc_index: index of the label component_name: layer_label: gc: ignored """ if component_name: name = component_name elif isinstance(port.parent, pp.Component): name = port.parent.name else: name = port.parent.ref_cell.name text = f"elec_{gc_index}_({name})_{port.name}" layer, texttype = pd._parse_layer(layer_label) label = pd.Label( text=text, position=port.midpoint, anchor="o", layer=layer, texttype=texttype, ) return label
def get_input_label( port: Port, gc: ComponentReference, gc_index: Optional[int] = None, gc_port_name: str = "o1", layer_label: Layer = gf.LAYER.LABEL, component_name: Optional[str] = None, get_input_label_text_function=get_input_label_text, ) -> Label: """Returns a label with component info for a given grating coupler. Test equipment to extract grating coupler coordinates and match it to the component. Args: port: port to label gc: grating coupler reference gc_index: grating coupler index gc_port_name: name of grating coupler port layer_label: layer of the label component_name: for the label get_input_label_text_function: function to get input label """ text = get_input_label_text_function(port=port, gc=gc, gc_index=gc_index, component_name=component_name) if gc_port_name is None: gc_port_name = list(gc.ports.values())[0].name layer, texttype = pd._parse_layer(layer_label) return Label( text=text, position=gc.ports[gc_port_name].midpoint, anchor="o", layer=layer, texttype=texttype, )
def add_fiber_single( component: Component, grating_coupler: Callable = grating_coupler_te, layer_label: Tuple[int, int] = LAYER.LABEL, optical_io_spacing: int = 50, bend_factory: Callable = bend_circular, straight_factory: Callable = waveguide, taper_factory: Callable = taper, taper_length: float = 10.0, route_filter: Callable = connect_strip_way_points, min_input2output_spacing: int = 127, optical_routing_type: int = 2, with_align_ports: bool = True, component_name: Optional[str] = None, gc_port_name: str = "W0", **kwargs, ) -> Component: r"""returns component with grating ports and labels on each port can add align_ports reference structure Args: component: to connect grating_coupler: grating coupler instance, function or list of functions layer_label: LAYER.LABEL optical_io_spacing: SPACING_GC bend_factory: bend_circular straight_factory: waveguide fanout_length: None # if None, automatic calculation of fanout length max_y0_optical: None with_align_ports: True, adds loopback structures waveguide_separation: 4.0 bend_radius: BEND_RADIUS list_port_labels: None, adds TM labels to port indices in this list connected_port_list_ids: None # only for type 0 optical routing nb_optical_ports_lines: 1 force_manhattan: False excluded_ports: grating_indices: None routing_method: connect_strip gc_port_name: W0 optical_routing_type: None: autoselection, 0: no extension gc_rotation: -90 component_name: name of component taper_factory: taper .. code:: fiber ______ /| | | / | | | W0| | | | \ | | | | \|_|_|_ | xmin = 0 .. plot:: :include-source: import pp from pp.routing import add_fiber_array c = pp.c.crossing() cc = add_fiber_array(c) pp.plotgds(cc) """ component = component() if callable(component) else component gc = grating_coupler = (grating_coupler() if callable(grating_coupler) else grating_coupler) gc_port_to_edge = abs(gc.xmax - gc.ports[gc_port_name].midpoint[0]) port_width_gc = grating_coupler.ports[gc_port_name].width optical_ports = component.get_ports_list(port_type="optical") port_width_component = optical_ports[0].width if port_width_component != port_width_gc: component = add_tapers( component, taper_factory(length=taper_length, width1=port_width_gc, width2=port_width_component), ) component_name = component_name or component.name name = f"{component_name}_{grating_coupler.name}" elements, grating_couplers = route_fiber_single( component, component_name=component_name, optical_io_spacing=optical_io_spacing, bend_factory=bend_factory, straight_factory=straight_factory, route_filter=route_filter, grating_coupler=grating_coupler, layer_label=layer_label, optical_routing_type=optical_routing_type, min_input2output_spacing=min_input2output_spacing, gc_port_name=gc_port_name, **kwargs, ) c = Component(name=name) cr = c << component cr.rotate(90) for e in elements: c.add(e) for gc in grating_couplers: c.add(gc) for pname, p in component.ports.items(): if p.port_type != "optical": c.add_port(pname, port=p) if isinstance(grating_coupler, list): grating_couplers = [call_if_func(g) for g in grating_coupler] grating_coupler = grating_couplers[0] else: grating_coupler = call_if_func(grating_coupler) grating_couplers = [grating_coupler] if with_align_ports: length = c.ysize - 2 * gc_port_to_edge wg = c << straight_factory(length=length) wg.rotate(90) wg.xmax = (c.xmin - optical_io_spacing if abs(c.xmin) > abs(optical_io_spacing) else c.xmin - optical_io_spacing) wg.ymin = c.ymin + gc_port_to_edge gci = c << grating_coupler gco = c << grating_coupler gci.connect(gc_port_name, wg.ports["W0"]) gco.connect(gc_port_name, wg.ports["E0"]) gds_layer_label, gds_datatype_label = pd._parse_layer(layer_label) port = wg.ports["E0"] text = get_optical_text(port, grating_coupler, 0, component_name=f"loopback_{component.name}") label = pd.Label( text=text, position=port.midpoint, anchor="o", layer=gds_layer_label, texttype=gds_datatype_label, ) c.add(label) port = wg.ports["W0"] text = get_optical_text(port, grating_coupler, 1, component_name=f"loopback_{component.name}") label = pd.Label( text=text, position=port.midpoint, anchor="o", layer=gds_layer_label, texttype=gds_datatype_label, ) c.add(label) return c