コード例 #1
0
ファイル: density.py プロジェクト: tvt173/gdsfactory
def compute_area(c: Component, target_layer: Tuple[int, int]) -> float64:
    """Returns Computed area of the component for a given layer."""
    # _print("Computing area ", c.name)
    c.flatten()
    # return c.area(by_spec=True)[layer]
    polys_by_spec = c.get_polygons(by_spec=True)
    _area = 0
    for (layer, polys) in polys_by_spec.items():
        # _print(layer)
        if layer == target_layer:
            joined_polys = gp.boolean(polys, None, operation="or")
            _print(joined_polys)
            try:
                _area += sum([abs(area(p)) for p in joined_polys.polygons])
            except BaseException:
                print(
                    f"Warning, {c.name} joinedpoly {joined_polys} could not be added"
                )
    return _area
コード例 #2
0
def get_transmission_2ports(
    component: Component,
    extend_ports_length: Optional[float] = 4.0,
    layer_core: int = 1,
    layer_source: int = 110,
    layer_monitor1: int = 101,
    layer_monitor2: int = 102,
    layer_simulation_region: int = 2,
    res: int = 20,
    t_clad_bot: float = 1.0,
    t_core: float = 0.22,
    t_clad_top: float = 1.0,
    dpml: int = 1,
    clad_material: Medium = mp.Medium(epsilon=2.25),
    core_material: Medium = mp.Medium(epsilon=12),
    is_3d: bool = False,
    run: bool = True,
    wavelengths: ndarray = np.linspace(1.5, 1.6, 50),
    field_monitor_point: Tuple[int, int, int] = (0, 0, 0),
    dfcen: float = 0.2,
) -> Dict[str, Any]:
    """Returns dict with Sparameters for a 2port gf.component

    requires source and  port monitors in the GDS

    based on meep directional coupler example
    https://meep.readthedocs.io/en/latest/Python_Tutorials/GDSII_Import/

    https://support.lumerical.com/hc/en-us/articles/360042095873-Metamaterial-S-parameter-extraction

    Args:
        component: gf.Component
        extend_ports_function: function to extend the ports for a component to ensure it goes beyond the PML
        layer_core: GDS layer for the Component material
        layer_source: for the source monitor
        layer_monitor1: monitor layer for port 1
        layer_monitor2: monitor layer for port 2
        layer_simulation_region: for simulation region
        res: resolution (pixels/um) For example: (10: 100nm step size)
        t_clad_bot: thickness for cladding below core
        t_core: thickness of the core material
        t_clad_top: thickness for cladding above core
        dpml: PML thickness (um)
        clad_material: material for cladding
        core_material: material for core
        is_3d: if True runs in 3D
        run: if True runs simulation, False only build simulation
        wavelengths: iterable of wavelengths to simulate
        field_monitor_point: monitors the field and stops simulation after field decays by 1e-9
        dfcen: delta frequency

    Returns:
        Dict:
            sim: simulation object

    Make sure you visualize the simulation region with gf.before you simulate a component

    .. code::

        import gdsfactory as gf
        import gmeep as gm

        component = gf.components.bend_circular()
        margin = 2
        cm = gm.add_monitors(component)
        cm.show()

    """
    assert isinstance(
        component, Component
    ), f"component needs to be a Component, got Type {type(component)}"
    if extend_ports_length:
        component = gf.components.extension.extend_ports(
            component=component, length=extend_ports_length, centered=True
        )
    component.flatten()
    gdspath = component.write_gds()
    gdspath = str(gdspath)

    freqs = 1 / wavelengths
    fcen = np.mean(freqs)
    frequency_width = dfcen * fcen
    cell_thickness = dpml + t_clad_bot + t_core + t_clad_top + dpml

    cell_zmax = 0.5 * cell_thickness if is_3d else 0
    cell_zmin = -0.5 * cell_thickness if is_3d else 0

    core_zmax = 0.5 * t_core if is_3d else 10
    core_zmin = -0.5 * t_core if is_3d else -10

    geometry = mp.get_GDSII_prisms(
        core_material, gdspath, layer_core, core_zmin, core_zmax
    )
    cell = mp.GDSII_vol(gdspath, layer_core, cell_zmin, cell_zmax)
    sim_region = mp.GDSII_vol(gdspath, layer_simulation_region, cell_zmin, cell_zmax)

    cell.size = mp.Vector3(
        sim_region.size[0] + 2 * dpml, sim_region.size[1] + 2 * dpml, sim_region.size[2]
    )
    cell_size = cell.size

    zsim = t_core + t_clad_top + t_clad_bot + 2 * dpml
    m_zmin = -zsim / 2
    m_zmax = +zsim / 2
    src_vol = mp.GDSII_vol(gdspath, layer_source, m_zmin, m_zmax)

    sources = [
        mp.EigenModeSource(
            src=mp.GaussianSource(fcen, fwidth=frequency_width),
            size=src_vol.size,
            center=src_vol.center,
            eig_band=1,
            eig_parity=mp.NO_PARITY if is_3d else mp.EVEN_Y + mp.ODD_Z,
            eig_match_freq=True,
        )
    ]

    sim = mp.Simulation(
        resolution=res,
        cell_size=cell_size,
        boundary_layers=[mp.PML(dpml)],
        sources=sources,
        geometry=geometry,
        default_material=clad_material,
    )
    sim_settings = dict(
        resolution=res,
        cell_size=cell_size,
        fcen=fcen,
        field_monitor_point=field_monitor_point,
        layer_core=layer_core,
        t_clad_bot=t_clad_bot,
        t_core=t_core,
        t_clad_top=t_clad_top,
        is_3d=is_3d,
        dmp=dpml,
    )

    m1_vol = mp.GDSII_vol(gdspath, layer_monitor1, m_zmin, m_zmax)
    m2_vol = mp.GDSII_vol(gdspath, layer_monitor2, m_zmin, m_zmax)
    m1 = sim.add_mode_monitor(
        freqs,
        mp.ModeRegion(center=m1_vol.center, size=m1_vol.size),
    )
    m1.z = 0
    m2 = sim.add_mode_monitor(
        freqs,
        mp.ModeRegion(center=m2_vol.center, size=m2_vol.size),
    )
    m2.z = 0

    # if 0:
    #     ''' Useful for debugging.  '''
    #     sim.run(until=50)
    #     sim.plot2D(fields=mp.Ez)
    #     plt.show()
    #     quit()

    r = dict(sim=sim, cell_size=cell_size, sim_settings=sim_settings)

    if run:
        sim.run(
            until_after_sources=mp.stop_when_fields_decayed(
                dt=50, c=mp.Ez, pt=field_monitor_point, decay_by=1e-9
            )
        )

        # call this function every 50 time spes
        # look at simulation and measure component that we want to measure (Ez component)
        # when field_monitor_point decays below a certain 1e-9 field threshold

        # Calculate the mode overlaps
        m1_results = sim.get_eigenmode_coefficients(m1, [1]).alpha
        m2_results = sim.get_eigenmode_coefficients(m2, [1]).alpha

        # Parse out the overlaps
        a1 = m1_results[:, :, 0]  # forward wave
        b1 = m1_results[:, :, 1]  # backward wave
        a2 = m2_results[:, :, 0]  # forward wave
        # b2 = m2_results[:, :, 1]  # backward wave

        # Calculate the actual scattering parameters from the overlaps
        s11 = np.squeeze(b1 / a1)
        s12 = np.squeeze(a2 / a1)
        s22 = s11.copy()
        s21 = s12.copy()

        # s22 and s21 requires another simulation, with the source on the other port
        # Luckily, if the device is symmetric, we can assume that s22=s11 and s21=s12.

        # visualize results
        plt.figure()
        plt.plot(
            wavelengths,
            10 * np.log10(np.abs(s11) ** 2),
            "-o",
            label="Reflection",
        )
        plt.plot(
            wavelengths,
            10 * np.log10(np.abs(s12) ** 2),
            "-o",
            label="Transmission",
        )
        plt.ylabel("Power (dB)")
        plt.xlabel(r"Wavelength ($\mu$m)")
        plt.legend()
        plt.grid(True)

        r.update(dict(s11=s11, s12=s12, s21=s21, s22=s22, wavelengths=wavelengths))
        keys = [key for key in r.keys() if key.startswith("S")]
        s = {f"{key}a": list(np.unwrap(np.angle(r[key].flatten()))) for key in keys}
        s_mod = {f"{key}m": list(np.abs(r[key].flatten())) for key in keys}
        s.update(**s_mod)
        s = pd.DataFrame(s)
    return r
コード例 #3
0
def import_gds(
    gdspath: Union[str, Path],
    cellname: Optional[str] = None,
    flatten: bool = False,
    snap_to_grid_nm: Optional[int] = None,
    name: Optional[str] = None,
    decorator: Optional[Callable] = None,
    gdsdir: Optional[Union[str, Path]] = None,
    **kwargs,
) -> Component:
    """Returns a Componenent from a GDS file.

    Adapted from phidl/geometry.py

    if any cell names are found on the component CACHE we append a $ with a
    number to the name

    Args:
        gdspath: path of GDS file.
        cellname: cell of the name to import (None) imports top cell.
        flatten: if True returns flattened (no hierarchy)
        snap_to_grid_nm: snap to different nm grid (does not snap if False)
        name: Optional name. Over-rides the default imported name.
        decorator: function to apply over the imported gds.
        gdsdir: optional GDS directory.
        kwargs: settings for the imported component (polarization, wavelength ...).
    """
    gdspath = Path(gdsdir) / Path(gdspath) if gdsdir else Path(gdspath)
    if not gdspath.exists():
        raise FileNotFoundError(f"No file {gdspath!r} found")

    metadata_filepath = gdspath.with_suffix(".yml")

    gdsii_lib = gdspy.GdsLibrary()
    gdsii_lib.read_gds(str(gdspath))
    top_level_cells = gdsii_lib.top_level()
    cellnames = [c.name for c in top_level_cells]

    if cellname is not None:
        if cellname not in gdsii_lib.cells:
            raise ValueError(
                f"cell {cellname} is not in file {gdspath} with cells {cellnames}"
            )
        topcell = gdsii_lib.cells[cellname]
    elif cellname is None and len(top_level_cells) == 1:
        topcell = top_level_cells[0]
    elif cellname is None and len(top_level_cells) > 1:
        raise ValueError(
            f"import_gds() There are multiple top-level cells in {gdspath!r}, "
            f"you must specify `cellname` to select of one of them among {cellnames}"
        )

    if name:
        if name in CACHE or name in CACHE_IMPORTED_CELLS:
            raise ValueError(
                f"name = {name!r} already on cache. "
                "Please, choose a different name or set name = None. ")
        else:
            topcell.name = name

    if flatten:
        component = Component(name=name or cellname or cellnames[0])
        polygons = topcell.get_polygons(by_spec=True)

        for layer_in_gds, polys in polygons.items():
            component.add_polygon(polys, layer=layer_in_gds)

        component = avoid_duplicated_cells(component)

    else:
        D_list = []
        cell_to_device = {}
        for c in gdsii_lib.cells.values():
            D = Component(name=c.name)
            D.polygons = c.polygons
            D.references = c.references
            D.name = c.name
            for label in c.labels:
                rotation = label.rotation
                if rotation is None:
                    rotation = 0
                label_ref = D.add_label(
                    text=label.text,
                    position=np.asfarray(label.position),
                    magnification=label.magnification,
                    rotation=rotation * 180 / np.pi,
                    layer=(label.layer, label.texttype),
                )
                label_ref.anchor = label.anchor

            D = avoid_duplicated_cells(D)
            D.unlock()

            cell_to_device.update({c: D})
            D_list += [D]

        for D in D_list:
            # First convert each reference so it points to the right Device
            converted_references = []
            for e in D.references:
                ref_device = cell_to_device[e.ref_cell]
                if isinstance(e, gdspy.CellReference):
                    dr = DeviceReference(
                        device=ref_device,
                        origin=e.origin,
                        rotation=e.rotation,
                        magnification=e.magnification,
                        x_reflection=e.x_reflection,
                    )
                    dr.owner = D
                    converted_references.append(dr)
                elif isinstance(e, gdspy.CellArray):
                    dr = CellArray(
                        device=ref_device,
                        columns=e.columns,
                        rows=e.rows,
                        spacing=e.spacing,
                        origin=e.origin,
                        rotation=e.rotation,
                        magnification=e.magnification,
                        x_reflection=e.x_reflection,
                    )
                    dr.owner = D
                    converted_references.append(dr)
            D.references = converted_references

            # Next convert each Polygon
            # temp_polygons = list(D.polygons)
            # D.polygons = []
            # for p in temp_polygons:
            #     D.add_polygon(p)

            # Next convert each Polygon
            temp_polygons = list(D.polygons)
            D.polygons = []
            for p in temp_polygons:
                if snap_to_grid_nm:
                    points_on_grid = snap_to_grid(p.polygons[0],
                                                  nm=snap_to_grid_nm)
                    p = gdspy.Polygon(points_on_grid,
                                      layer=p.layers[0],
                                      datatype=p.datatypes[0])
                D.add_polygon(p)
        component = cell_to_device[topcell]
        cast(Component, component)

    name = name or component.name
    component.name = name

    if metadata_filepath.exists():
        logger.info(f"Read YAML metadata from {metadata_filepath}")
        metadata = OmegaConf.load(metadata_filepath)

        for port_name, port in metadata.ports.items():
            if port_name not in component.ports:
                component.add_port(
                    name=port_name,
                    midpoint=port.midpoint,
                    width=port.width,
                    orientation=port.orientation,
                    layer=port.layer,
                    port_type=port.port_type,
                )

        component.info = metadata.info

    component.info.update(**kwargs)
    component.name = name
    component.info.name = name

    if decorator:
        component_new = decorator(component)
        component = component_new or component
    if flatten:
        component.flatten()
    component.lock()
    return component