Source code for gdsfactory.components.pack_doe

from __future__ import annotations

import itertools as it
from typing import Any

import gdsfactory as gf
from gdsfactory.component import Component
from gdsfactory.grid import grid, grid_with_text
from gdsfactory.pack import pack
from gdsfactory.typings import CellSpec, ComponentSpec


def generate_doe(
    doe: ComponentSpec,
    settings: dict[str, list[Any]],
    do_permutations: bool = False,
    function: CellSpec | None = None,
) -> tuple[tuple[Component, ...], tuple[dict, ...]]:
    """Generates a component DOE (Design of Experiment).

    which can then be packed, or used elsewhere.

    Args:
        doe: function to return Components.
        settings: component settings.
        do_permutations: for each setting.
        function: for the component (add padding, grating couplers ...)
    """
    if do_permutations:
        settings_list = [dict(zip(settings, t)) for t in it.product(*settings.values())]
    else:
        settings_list = [dict(zip(settings, t)) for t in zip(*settings.values())]

    if function:
        function = gf.get_cell(function)
        if not callable(function):
            raise ValueError(f"Error {function!r} needs to be callable.")
        component_list = [
            function(gf.get_component(doe, **settings)) for settings in settings_list
        ]
    else:
        component_list = [
            gf.get_component(doe, **settings) for settings in settings_list
        ]

    component_list = tuple(component_list)
    settings_list = tuple(settings_list)
    return component_list, settings_list


[docs] def pack_doe( doe: ComponentSpec, settings: dict[str, tuple[Any, ...]], do_permutations: bool = False, function: CellSpec | None = None, **kwargs: Any, ) -> Component: """Packs a component DOE (Design of Experiment) using pack. Args: doe: function to return Components. settings: component settings. do_permutations: for each setting. function: to apply (add padding, grating couplers). kwargs: for pack. Keyword Args: spacing: Minimum distance between adjacent shapes. aspect_ratio: (width, height) ratio of the rectangular bin. max_size: Limits the size into which the shapes will be packed. sort_by_area: Pre-sorts the shapes by area. density: Values closer to 1 pack tighter but require more computation. precision: Desired precision for rounding vertex coordinates. text: Optional function to add text labels. text_prefix: for labels. For example. 'A' for 'A1', 'A2'... text_offsets: relative to component size info anchor. Defaults to center. text_anchors: relative to component (ce cw nc ne nw sc se sw center cc). name_prefix: for each packed component (avoids the Unnamed cells warning). Note that the suffix contains a uuid so the name will not be deterministic. rotation: for each component in degrees. h_mirror: horizontal mirror in y axis (x, 1) (1, 0). This is the most common. v_mirror: vertical mirror using x axis (1, y) (0, y). """ component_list, settings_list = generate_doe( doe=doe, settings=settings, do_permutations=do_permutations, function=function ) c = pack(component_list, **kwargs) if len(c) > 1: raise ValueError( f"failed to pack in one Component, it created {len(c)} Components" ) c = c[0] c.doe_names = [component.name for component in component_list] c.doe_settings = settings_list return c
[docs] def pack_doe_grid( doe: ComponentSpec, settings: dict[str, tuple[Any, ...]], do_permutations: bool = False, function: CellSpec | None = None, with_text: bool = False, **kwargs: Any, ) -> Component: """Packs a component DOE (Design of Experiment) using grid. Args: doe: function to return Components. settings: component settings. do_permutations: for each setting. function: to apply to component (add padding, grating couplers). with_text: includes text label. kwargs: for grid. Keyword Args: spacing: between adjacent elements on the grid, can be a tuple for different distances in height and width. separation: If True, guarantees elements are separated with fixed spacing if False, elements are spaced evenly along a grid. shape: x, y shape of the grid (see np.reshape). If no shape and the list is 1D, if np.reshape were run with (1, -1). align_x: {'x', 'xmin', 'xmax'} for x (column) alignment along. align_y: {'y', 'ymin', 'ymax'} for y (row) alignment along. edge_x: {'x', 'xmin', 'xmax'} for x (column) (ignored if separation = True). edge_y: {'y', 'ymin', 'ymax'} for y (row) (ignored if separation = True). rotation: for each component in degrees. h_mirror: horizontal mirror y axis (x, 1) (1, 0). most common mirror. v_mirror: vertical mirror using x axis (1, y) (0, y). """ if do_permutations: settings_list = [dict(zip(settings, t)) for t in it.product(*settings.values())] else: settings_list = [dict(zip(settings, t)) for t in zip(*settings.values())] if function: function = gf.get_cell(function) if not callable(function): raise ValueError(f"Error {function!r} needs to be callable.") component_list = [ function(gf.get_component(doe, **settings)) for settings in settings_list ] else: component_list = [ gf.get_component(doe, **settings) for settings in settings_list ] component_list = tuple(component_list) settings_list = tuple(settings_list) if with_text: c = grid_with_text(component_list, **kwargs) else: c = grid(component_list, **kwargs) c.doe_names = [component.name for component in component_list] c.doe_settings = settings_list return c
if __name__ == "__main__": c = pack_doe_grid( doe="mmi1x2", settings=dict(length_mmi=(2.5, 100), width_mmi=(4, 10)), with_text=True, spacing=(100, 100), shape=(2, 2), do_permutations=True, ) c = pack_doe(doe="mmi1x2", settings=dict(length_mmi=[2, 100], width_mmi=[4, 10])) # c = pack_doe() c.show()