Coder Social home page Coder Social logo

gdsfactory / gdatasea Goto Github PK

View Code? Open in Web Editor NEW
2.0 2.0 0.0 18 KB

Database models for measurements and analysis as it pertains to chip designs

Python 74.95% CSS 0.69% HTML 22.41% Dockerfile 0.53% JavaScript 0.44% Mako 0.49% Jinja 0.24% Makefile 0.24%
database

gdatasea's Introduction

GDSFactory 8.7.3

docs PyPI PyPI Python Downloads MIT codecov Binder Colab

🚀 Notice: Major Release

We are excited to announce that GDSFactory has upgraded its backend from gdstk to KLayout. This change brings enhanced routing functions and additional features from KLayout, including DRC, dummy fill, and connectivity checks.

Notice that the routing and some advanced functions have changed. For a complete list of changes, please refer to our migration guide or review the updated layout tutorial.

GDSFactory is a powerful Python library for designing a wide range of complex systems, including photonic circuits, analog devices, quantum components, MEMs, 3D printed objects, and PCBs. With GDSFactory, you can create and refine your designs using Python or YAML, perform rigorous verification through Design Rule Checking (DRC), Layout Versus Schematic (LVS) checks, and simulations. Additionally, it facilitates automated lab testing to ensure that your fabricated devices meet precise specifications, streamlining the entire design-to-fabrication workflow.

As input you write python code, as an output GDSFactory creates CAD files (GDS, OASIS, STL, GERBER).

cad

Highlights:

  • +2M downloads
  • +65 Contributors
  • +15 PDKs available

workflow

We provide a comprehensive end-to-end design flow that enables you to:

  • Design (Layout, Simulation, Optimization): Define parametric cell functions in Python to generate components. Test component settings, ports, and geometry to avoid unwanted regressions, and capture design intent in a schematic.
  • Verify (DRC, DFM, LVS): Run simulations directly from the layout using our simulation interfaces, removing the need to redraw your components in simulation tools. Conduct component and circuit simulations, study design for manufacturing. Ensure complex layouts match their design intent through Layout Versus Schematic verification (LVS) and are DRC clean.
  • Validate: Define layout and test protocols simultaneously for automated chip analysis post-fabrication. This allows you to extract essential component parameters, and build data pipelines from raw data to structured data to monitor chip performance.

Your input: Python or YAML text. Your output: A GDSII or OASIS file for fabrication, alongside component settings (for measurement and data analysis) and netlists (for circuit simulations) in YAML.

We provide a common syntax for design (Ansys, Lumerical, Tidy3d, MEEP, DEVSIM, SAX, MEOW, Xyce ...), verification, and validation.

tool interfaces

Numerous foundries offer GDSFactory PDKs that are accessible under an NDA. To gain access to these PDKs, please send proof of your NDA to [email protected]

  • AIM photonics PDK
  • AMF photonics PDK
  • Compoundtek photonics PDK
  • GlobalFoundries 45SPCLO Photonics PDK
  • HHI Photonics PDK
  • IMEC photonics PDK
  • Smart Photonics Photonics PDK
  • TowerSemi PH18 photonics PDK
  • III-V Labs PDK
  • Lionix PDK

Coming soon:

  • Ligentec PDK

There are also open source PDKs available without an NDA:

Getting started

Who is using GDSFactory?

Hundreds of organisations are using GDSFactory. Some companies and organizations around the world using GDSFactory include:

logos

"I've used GDSFactory since 2017 for all my chip tapeouts. I love that it is fast, easy to use, and easy to extend. It's the only tool that allows us to have an end-to-end chip design flow (design, verification and validation)."

Joaquin Matres - Google

"I've relied on GDSFactory for several tapeouts over the years. It's the only tool I've found that gives me the flexibility and scalability I need for a variety of projects."

Alec Hammond - Meta Reality Labs Research

"The best photonics layout tool I've used so far and it is leaps and bounds ahead of any commercial alternatives out there. Feels like GDSFactory is freeing photonics."

Hasitha Jayatilleka - LightIC Technologies

"As an academic working on large scale silicon photonics at CMOS foundries I've used GDSFactory to go from nothing to full-reticle layouts rapidly (in a few days). I particularly appreciate the full-system approach to photonics, with my layout being connected to circuit simulators which are then connected to device simulators. Moving from legacy tools such as gdspy and phidl to GDSFactory has sped up my workflow at least an order of magnitude."

Alex Sludds - MIT

"I use GDSFactory for all of my photonic tape-outs. The Python interface makes it easy to version control individual photonic components as well as entire layouts, while integrating seamlessly with KLayout and most standard photonic simulation tools, both open-source and commercial.

Thomas Dorch - Freedom Photonics

Why use GDSFactory?

  • It's fast, extensible and easy to use.
  • It's free, as in freedom and in cost.
  • It's the most popular EDA tool with a growing community of users, developers, and extensions to other tools.

GDSFactory is really fast thanks to KLayout C++ library for manipulating GDSII objects. You will notice this when reading/writing big GDS files or doing large boolean operations.

Benchmark gdspy GDSFactory Gain
10k_rectangles 80.2 ms 4.87 ms 16.5
boolean-offset 187 μs 44.7 μs 4.19
bounding_box 36.7 ms 170 μs 216
flatten 465 μs 8.17 μs 56.9
read_gds 2.68 ms 94 μs 28.5

Contributors

Thanks to all the contributors that make this awesome project possible!

contributors

gdatasea's People

Contributors

dependabot[bot] avatar ealameda31 avatar joamatab avatar sebastian-goeldi avatar yaugenst avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

doplaydo yaugenst

gdatasea's Issues

Clean up and refine Auto-Populator

The auto-populator should probably not live in the standard code base but rather either in separate folder or maybe even just be accessible in the development (git) installation and not be part of the main module.

somethings like.

|--- gdatasea
|------ gdatasea
|--------- __init__.py
|--------- ...
|------ tests
|--------- ...
|------ populator.py
|------ pyproject.toml
|------ ...

Maybe we can also use the seali.requests instead? That one is without all the typer stuff, exactly for something like this

Test Cases for EDAFile

No object (all/all)
Object with only parent (cells/only parent)
Object with more than one parent (cells/only parent)
Object with parent/children (cells/parent and children)
Object with multiple parent/children (cells/parents and children)
Object with bad parent (NA/NA)
Object with bad parent/ good wildcard (NA/NA)
Object with good parent/bad wildcard (cells/only parent)
Object with good parent/ unspecified wildcard but still empty string (cells/parent and children)

Auto-Populator

gen_mzi_gds.py
import kfactory as kf
from functools import partial
from typing import Literal
import numpy as np


class LAYER(kf.LayerEnum):
    kcl = kf.constant(kf.kcl)
    WG = (1, 0)
    ETCH = (2, 0)
    BORDER = (10, 0)


bend = kf.cells.circular.bend_circular(width=1, radius=10, layer=LAYER.WG)
bend180 = kf.cells.circular.bend_circular(width=1, radius=10, layer=LAYER.WG, angle=180)


s_f = partial(kf.cells.straight.straight, layer=LAYER.WG)
s_f_dbu = partial(kf.cells.straight.straight_dbu, layer=LAYER.WG)


@kf.cell
def mmi(
    taper_length: int = 2_000,
    taper_width1: int = 1_000,
    taper_width2: int = 1_5000,
    body_width: int = 2_000,
    body_length: int = 12_000,
):
    c = kf.KCell()

    c.shapes(LAYER.WG).insert(kf.kdb.Box(12_000, 4_000))
    poly = kf.kdb.Polygon(
        [
            kf.kdb.Point(-2000, -500),
            kf.kdb.Point(-2000, 500),
            kf.kdb.Point(0, 750),
            kf.kdb.Point(0, -750),
        ]
    )
    c.shapes(LAYER.WG).insert(poly.transformed(kf.kdb.Trans(0, False, -6_000, 1_000)))
    c.shapes(LAYER.WG).insert(poly.transformed(kf.kdb.Trans(0, False, -6_000, -1_000)))
    c.shapes(LAYER.WG).insert(poly.transformed(kf.kdb.Trans(2, False, 6_000, 0)))

    c.create_port(
        trans=kf.kdb.Trans(2, False, -8_000, -1000), width=1000, layer=LAYER.WG
    )
    c.create_port(
        trans=kf.kdb.Trans(2, False, -8_000, 1000), width=1000, layer=LAYER.WG
    )
    c.create_port(trans=kf.kdb.Trans(8_000, 0), width=1000, layer=LAYER.WG)
    c.autorename_ports()

    return c


@kf.cell
def mzi(delta_l: int) -> kf.KCell:
    c = kf.KCell()
    mmi1 = c << mmi()
    mmi2 = c << mmi()

    b1 = c << bend
    b1.connect("o1", mmi1, "o2", mirror=True)
    b2 = c << bend180
    b3 = c << bend

    s = s_f(width=1, length=delta_l / 2)
    s1 = c << s
    s2 = c << s
    s1.connect("o1", b1, "o2")
    b2.connect("o2", s1, "o2")
    s2.connect("o1", b2, "o1")
    b3.connect("o1", s2, "o2")
    mmi2.connect("o2", b3, "o2")

    b1 = c << bend
    b2 = c << bend180
    b3 = c << bend

    b1.connect("o1", mmi1, "o1")
    b2.connect("o2", b1, "o2")
    b3.connect("o1", b2, "o1")

    c.add_port(mmi1.ports["o3"])
    c.add_port(mmi2.ports["o3"])
    c.autorename_ports()

    return c


@kf.cell
def mzi_test(delta_l: int) -> kf.KCell:
    c = kf.KCell()

    gcs = [
        c
        << grating_coupler_elliptical_te(
            wg_width=1,
        )
        for _ in range(4)
    ]
    for i in range(4):
        gc = gcs[i]
        gc.rotate(3)
        gc.movex(200000 * i)

    mzi1 = c << mzi(delta_l=delta_l)
    mzi1.move((mzi1.bbox().center().x, mzi1.bbox().bottom), (300000, 20_000))
    kf.routing.optical.route(
        c,
        mzi1.ports["o1"],
        gcs[1].ports["o1"],
        straight_factory=s_f_dbu,
        bend90_cell=bend,
    )
    kf.routing.optical.route(
        c,
        mzi1.ports["o2"],
        gcs[2].ports["o1"],
        straight_factory=s_f_dbu,
        bend90_cell=bend,
    )

    kf.routing.optical.place90(
        c,
        gcs[0].ports["o1"],
        gcs[3].ports["o1"],
        kf.routing.optical.route_loopback(
            gcs[0].ports["o1"],
            gcs[3].ports["o1"],
            bend90_radius=10_000,
            # bend180_radius=10_000,
            d_loop=60_000,
        ),
        straight_factory=s_f_dbu,
        bend90_cell=bend,
    )

    return c


@kf.cell
def CHIPLET1() -> kf.KCell:
    c = kf.KCell()

    p = kf.kdb.Point(0, 0)
    for i in range(10):
        mzi = c << mzi_test(i * 10)
        mzi.transform(
            kf.kdb.Trans(p.to_v())
            * kf.kdb.Trans(mzi.bbox().left, mzi.bbox().bottom).inverted()
        )
        p = kf.kdb.Point(mzi.bbox().right + 50_000, mzi.bbox().bottom)
    c.info.d_l_min = 0
    c.info.d_l_max = 90
    c.info.d_l_step = 10

    c.shapes(LAYER.BORDER).insert(c.bbox().enlarged(100))

    return c


@kf.cell
def CHIPLET2() -> kf.KCell:
    c = kf.KCell()

    p = kf.kdb.Point(0, 0)
    for i in range(
        10,
        21,
    ):
        mzi = c << mzi_test(i * 1)
        mzi.transform(
            kf.kdb.Trans(p.to_v())
            * kf.kdb.Trans(mzi.bbox().left, mzi.bbox().bottom).inverted()
        )
        p = kf.kdb.Point(mzi.bbox().right + 50_000, mzi.bbox().bottom)

    c.info.d_l_min = 10
    c.info.d_l_max = 20
    c.info.d_l_step = 1

    c.shapes(LAYER.BORDER).insert(c.bbox().enlarged(100))

    return c


@kf.cell
def CHIP() -> kf.KCell:
    c = kf.KCell()

    c1 = c << CHIPLET1()
    c2 = c << CHIPLET2()
    c2.movey(c2.bbox().bottom, c1.bbox().top + 10_000)

    return c


@kf.cell
def grating_coupler_elliptical(
    polarization: Literal["te"] | Literal["tm"] = "te",
    taper_length: float = 20,
    taper_angle: float = 40,
    trenches_extra_angle: float = 10,
    lambda_c: float = 1.5,
    fiber_angle: float = 15,
    grating_line_width: float = 0.250,
    wg_width: float = 0.5,
    neff: float = 2.6,  # tooth effective index
    layer_taper: LAYER | None = LAYER.WG,
    layer_trench: LAYER = LAYER.ETCH,
    p_start: int = 26,
    n_periods: int = 30,
    taper_offset: int = 0,
    taper_extent_n_periods: float | Literal["first"] | Literal["last"] = "last",
    period: int | None = None,
    x_fiber_launch: int | None = None,
    clad_index: float = 1.4,  # cladding index
) -> kf.KCell:
    DEG2RAD = np.pi / 180
    sthc = np.sin(fiber_angle * DEG2RAD)

    if period is not None:
        neff = lambda_c / period + clad_index * sthc

    d = neff**2 - clad_index**2 * sthc**2
    a1 = lambda_c * neff / d
    b1 = lambda_c / np.sqrt(d)
    x1 = lambda_c * clad_index * sthc / d

    # a1 = round(a1 * 1e3)
    # b1 = round(b1 * 1e3)
    # x1 = round(x1 * 1e3)

    _period = a1 + x1

    trench_line_width = _period - grating_line_width

    c = kf.KCell()
    c.info["polarization"] = polarization
    c.info["wavelength"] = lambda_c * 1e3

    # Make each grating line

    for p in range(p_start, p_start + n_periods + 2):
        tooth = grating_tooth(
            (p - 0.5) * a1,
            (p - 0.5) * b1,
            (p - 0.5) * x1,
            trench_line_width,
            taper_angle + trenches_extra_angle,
        )
        c.shapes(layer_trench).insert(tooth)
    kf.kdb.Region(c.shapes(layer_trench))

    # Make the taper
    if taper_extent_n_periods == "last":
        n_periods_over_grating: float = n_periods + 1
    elif taper_extent_n_periods == "first":
        n_periods_over_grating = -1.5
    else:
        n_periods_over_grating = taper_extent_n_periods

    def _get_taper_pts(
        n_periods_over_grating: float,
    ) -> tuple[list[kf.kdb.DPoint], float]:
        p_taper = p_start + n_periods_over_grating
        _taper_length = taper_length + (n_periods_over_grating - 1) * _period

        a_taper = a1 * p_taper
        b_taper = b1 * p_taper
        x_taper = x1 * p_taper

        x_output = a_taper + x_taper - _taper_length + grating_line_width / 2
        taper_pts = grating_taper_points(
            a_taper,
            b_taper,
            x_output,
            x_taper + _period,
            taper_angle,
            wg_width=wg_width,
        )
        return taper_pts, x_output

    taper_pts, x_output = _get_taper_pts(n_periods_over_grating=n_periods_over_grating)
    if layer_taper is not None:
        c.shapes(layer_taper).insert(
            kf.kdb.DPolygon(taper_pts).transformed(kf.kdb.Trans(taper_offset, 0))
        )
        c.create_port(
            name="o1",
            trans=kf.kdb.Trans.R180,
            width=int(wg_width / c.kcl.dbu),
            layer=layer_taper,
        )

    c.transform(kf.kdb.Trans(int(-x_output - taper_offset), 0))

    # Add port
    c.info["period"] = _period

    # Add GC Fibre launch reference port, we are putting it at the same place
    # as the other I/O port for now
    x0 = p_start * a1 - grating_line_width + 9

    x_fiber_launch = x0 if x_fiber_launch is None else x_fiber_launch
    c.create_port(
        name="FL",
        trans=kf.kdb.Trans(x_fiber_launch, 0),
        layer=LAYER.WG,
        width=100,
        port_type="fibre_launch",
    )
    y0 = 0
    c.info.p0_overclad_x0 = x0
    c.info.p0_overclad_y0 = y0
    return c


def grating_tooth(
    ap: float,
    bp: float,
    xp: int,
    width: int,
    taper_angle: float,
    spiked: bool = True,
    angle_step: float = 1.0,
) -> kf.kdb.Region:
    angle_min = -taper_angle / 2
    angle_max = taper_angle / 2

    backbone_points = ellipse_arc(ap, bp, xp, angle_min, angle_max, angle_step)
    return (
        _extracted_from_grating_tooth_15(width, backbone_points)
        if spiked
        else kf.kdb.Region(kf.kdb.Path(backbone_points, width))
    )


# TODO Rename this here and in `grating_tooth`
def _extracted_from_grating_tooth_15(width, backbone_points):
    spike_length = width // 3
    path = kf.kdb.DPath(backbone_points, width).polygon()
    edges = kf.kdb.Edges([path.to_itype(kf.kcl.dbu)])
    bb_edges = kf.kdb.Edges(
        [
            kf.kdb.DEdge(backbone_points[0], backbone_points[1]).to_itype(kf.kcl.dbu),
            kf.kdb.DEdge(backbone_points[-1], backbone_points[-2]).to_itype(kf.kcl.dbu),
        ]
    )
    border_edges = edges.interacting(bb_edges)
    result = kf.kdb.Region([path.to_itype(kf.kcl.dbu)])
    for edge in border_edges.each():
        shifted = edge.shifted(spike_length)
        shifted_center = (shifted.p1 + shifted.p2.to_v()) / 2
        result.insert(kf.kdb.Polygon([edge.p1, shifted_center, edge.p2]))
    result.merge()

    return result


def grating_taper_points(
    a: float,
    b: float,
    x0: int,
    taper_length: float,
    taper_angle: float,
    wg_width: float,
    angle_step: float = 1.0,
) -> list[kf.kdb.DPoint]:
    taper_arc = ellipse_arc(
        a, b, taper_length, -taper_angle / 2, taper_angle / 2, angle_step=angle_step
    )

    p0 = kf.kdb.DPoint(x0, wg_width / 2)
    p1 = kf.kdb.DPoint(x0, -wg_width / 2)
    return [p0, p1] + taper_arc


def ellipse_arc(
    a: float,
    b: float,
    x0: float,
    angle_min: float,
    angle_max: float,
    angle_step: float = 0.5,
) -> list[kf.kdb.DPoint]:
    angle = np.arange(angle_min, angle_max + angle_step, angle_step) * np.pi / 180
    xs = a * np.cos(angle) + x0
    ys = b * np.sin(angle)
    return [kf.kdb.DPoint(x, y) for x, y in zip(xs, ys)]  # np.column_stack([xs, ys])


grating_coupler_elliptical_te = partial(
    grating_coupler_elliptical,
    polarization="te",
    taper_length=20,
    taper_angle=40,
    lambda_c=1.5,
    fiber_angle=15,
    grating_line_width=0.250,
    wg_width=0.500,
    p_start=26,
    n_periods=30,
    taper_offset=-0.30,
    x_fiber_launch=None,
)

if __name__ == "__main__":
    CHIP()
    kf.kcl.write("mzi_chip.gds")
    kf.show("mzi_chip.gds")

seali

sea project create mzi_chip.gds --name "MZI_CHIP" --top-cell CHIPLET1 --wildcards "mzi_test" --top-cell CHIPLET2 --wildcards "mzi_test"

TODO

  • seali upload data to at least these two devices CHIPLET1_mzi_test_DL10_711500_60500, CHIPLET2_mzi_test_DL10_20500_60500

Add LayerProperty File to EDAFile

If we store the layerproperty file with the EDAFile, we can a) use it in the renderer (add ?...&layer_props=/folder/path/file.gds) and b) it allows users to find the proper visualization for their projects/tapeouts easily

uploading files

I uploaded a 10MB mask and the file is taking more than 10min ...

  • why is this slow?
  • can we track progress?
  • Can we upload only cells that are going to be tested? For example mark them with labels

@Ealameda31
@tvt173
@sebastian-goeldi

Finish initial edafile view

edafile is looking great now with @sebastian-goeldi's integration of kweb.

We are still missing the following on the page before we move onto cells:

  • New button that allows upload of gdsfile, layer yml colors, and device wildcard matching

    • this means we need an endpoint and storage for the wildcard matching json
    • we would also need to modify code to only parse the cells matching the wildcards
  • Search capabilities in the navbar for convenience

  • Probably an update button based on edafile name for users to overwrite their gds

cc @joamatab

move database models from gplugins.models into gdatasea

The idea of gdsfactory is to provide an end to end solution, including design, verification and validation (testing in the lab).

We moved the gdsfactory.plugins.database code into plugins.database. See docs here

Now we are in the process of expanding the database code into gdatasea, which will include a webapp for visualizing measurements and simulations and link them to the device layouts

I'd like to start pushing lab data and simulations into gdatasea

How can we include the models from gplugins.database into gdatasea?

Ideally we can also show an integration with the major lab automation frameworks

@bmoneke
@vgvelev

Make API doc examples native; switch out project endpoints

In the midst of @joamatab making us realize that people will just not read documentation, we should make two endpoints.

  1. Post project name, description, and cell wildcards (with native openapi examples https://fastapi.tiangolo.com/tutorial/schema-extra-example/#openapi-specific-examples)
  2. Post files to project based on project name

This will mitigate people from posting large GDS and causing the server to overload reading millions of devices until we have our background job runner.

Thoughts? @sebastian-goeldi

Inefficient GDS -> cell parsing

How we currently extract the cells from the GDS involves three for loops where cell names and meta information are accessed before the final loop.

Wafer/Die need endpoints

Would be great to have a populator that posts a bunch of different measurements/simulations on different devices on the same project for different wafer/dies.

Need to re-evaluate put (re-analyzing) project

Would be very ideal if we can get this working as it should. Will move this out of MVP for now.

cc @joamatab
cc @sebastian-goeldi

@project_router.put("/{project_name}")
async def put_project(
    project_name: str,
    eda_file: UploadFile,
    lyp_file: Optional[UploadFile] = None,
    description: Optional[str] = None,
    cell_wildcards: list[CellWildcard] = Body(default=[]),
    session: Session = Depends(get_session)
):
    project = session.query(Project).filter(Project.name == project_name).one_or_none()

    if not project:
        return HTTPException(400, "Project was not found in the database")
    
    session.query(Project).filter(Project.id == project.id).update({"name": project_name, "description": description, ""})
    session.commit()

    return {"statuscode": 200}
    session.(project)
    session.commit()

    return await post_project(project.name, eda_file, lyp_file, description, cell_wildcards, session)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.