01 · From a GDS layout to a Component

Every simulation starts with geometry. gds_fdtd reads a GDS cell against a technology and produces a Component — device polygons, a material stack, and auto-detected ports — the object every engine consumes. This first step is entirely offline (KLayout + matplotlib), no engine required.

Here we load a waveguide crossing shipped with the examples.

from pathlib import Path

import matplotlib.pyplot as plt

from gds_fdtd.lyprocessor import load_cell
from gds_fdtd.plotting import plot_component
from gds_fdtd.simprocessor import load_component_from_tech
from gds_fdtd.spec import SimulationSpec
from gds_fdtd.technology import Technology


def _find(rel: str) -> Path:
    for base in (Path.cwd(), *Path.cwd().parents):
        if (base / rel).exists():
            return base / rel
    raise FileNotFoundError(rel)

1 · Load the cell against a technology

load_cell opens the GDS and picks the top cell; load_component_from_tech extrudes each layer’s polygons to the z-heights and materials the technology defines, and detects ports from the pin/DevRec layers. The technology is what turns 2-D polygons into a 3-D, materialized device.

tech = Technology.from_yaml(_find("examples/tech.yaml"))
cell, layout = load_cell(str(_find("examples/devices.gds")), top_cell="crossing_te1550")
component = load_component_from_tech(cell=cell, tech=tech)
print(f"loaded {component.name!r}")
00:26:11 PDT WARNING: Using canonical configuration directory at                
             '/home/mustafa/.config/tidy3d'. Found legacy directory at          
             '~/.tidy3d', which will be ignored. Remove it manually or run      
             'tidy3d config migrate --delete-legacy' to clean up.               
loaded 'crossing_te1550'

2 · Ports — detected automatically

A crossing has four ports. Each carries its own name, µm coordinates, width, and a snapped direction (0/90/180/270°) — everything an engine needs to launch and collect modes.

for p in component.ports:
    print(f"  {p.name}: center ({p.center[0]:.2f}, {p.center[1]:.2f}, {p.center[2]:.2f}) µm, "
          f"width {p.width:.3f} µm, facing {p.direction}°")
  opt1: center (-4.80, 0.00, 0.11) µm, width 0.500 µm, facing 180°
  opt4: center (4.80, 0.00, 0.11) µm, width 0.500 µm, facing 0°
  opt2: center (0.00, 4.80, 0.11) µm, width 0.500 µm, facing 90°
  opt3: center (0.00, -4.80, 0.11) µm, width 0.500 µm, facing 270°

3 · Structures — role-tagged, materialized

The component is a flat list of structures, each tagged by role (device / substrate / superstrate), with its GDS layer, z-extent, and resolved material. Backgrounds (substrate/superstrate) are filled by the technology, not the GDS.

for s in component.structures:
    print(f"  {s.role:<11} {s.name:<10} layer {s.layer}  z {s.z_base:+.2f}{s.z_base + s.z_span:+.2f} µm")
b = component.bounds
print(f"\nbounds: x [{b.x_min:.2f}, {b.x_max:.2f}]  y [{b.y_min:.2f}, {b.y_max:.2f}]  "
      f"z-center {b.z_center:.3f} µm")
  substrate   Substrate  layer [999, 0]  z +0.00…-2.00 µm
  superstrate Superstrate layer [999, 1]  z +0.00…+3.00 µm
  device      dev_0_0    layer [1, 0]  z +0.00…+0.22 µm

bounds: x [-4.80, 4.80]  y [-4.80, 4.80]  z-center 0.110 µm

4 · The geometry view

The standard picture: device polygons (per layer), the detected ports (arrows + width ticks), the devrec bounds, and — given a SimulationSpec — the FDTD region and the port-extension stubs the solvers push through the PML. Each simulation notebook opens with this geometry view.

plot_component(component, spec=SimulationSpec(buffer=1.0))
plt.show()
../_images/499c7042649dec2ecfcd5cfd144aeaa20d6dc63182f48e0d89407bef16a4d84e.png

5 · The same component in 3D

show_3d renders the extruded stack interactively — drag to orbit, scroll to zoom, click any object for its name, material, and z-extent; the legend toggles layers, ports, and the translucent substrate/superstrate. It works in the notebook and in this documentation page alike (the static fallback for JavaScript-free contexts is viewer3d.render_static).

from gds_fdtd.viewer3d import show_3d  # noqa: E402

show_3d(component, height=420)
del layout  # release the KLayout objects

Recap & next

One Component — geometry + materials + ports — is all any engine needs, and it came from a plain GDS file plus a technology. The rest of the toolbox works the same regardless of the source.

  • 02_technology — the material side of that technology.

  • 03_first_simulation — put this Component through an FDTD engine.

  • 08_frontends — the same Component from gdsfactory / SiEPIC / raw GDS.