## First example: straight waveguide ### Creating structures and exporting to GDS The GDS file format stores structure data as a collection of layers, each representing a 2D layout. Therefore, GDS inherently describes stacks of 2D patterns rather than true 3D geometries. This means it cannot directly represent fully three-dimensional features, such as cone-shaped metasurfaces or microring support posts, which may require gray-scale lithography. Additionally, GDS files do not natively include material information—although this can be supplemented by separate LayerMap or LayerStack files. For simulations involving such cases, additional tools or methods are required (e.g., CAD software for complex 3D shapes, or specifying materials in the simulation environment via a layer map). We will start with simple examples. It is important to note that for advanced fabrication, the GDS layouts used for simulation and for actual processing may differ. In this notebook, we will focus on simulation-oriented layouts. ### Straight Si waveguide with cladding For a simple straight waveguide structure, you may write: ```python import gdsfactory as gf # Create a 10 micron long, 500 nm wide straight waveguide (default Si layer, all unit is micron) c = gf.components.straight(length=10, width=0.5) c.plot() c.write_gds("builtin_straight_si.gds") ``` The function `gf.components.straight` generates a straight waveguide component and belongs to the `components` module in gdsfactory (https://gdsfactory.github.io/gdsfactory/notebooks/00_geometry.html). `components` allows you to draw polygons, texts, and `connect` some components via ports. This can be checked by ```python for port in c.ports: print( f"name={port.name}, center={port.center}, orientation={port.orientation}, " f"width={port.width}, layer={port.layer}" ) ``` Output would be ``` name=o1, center=(0.0, 0.0), orientation=180.0, width=0.5, layer=1 name=o2, center=(10.0, 0.0), orientation=0.0, width=0.5, layer=1 ``` >[!Note]- > Always define ports for each component, even for simple structures such as photodetectors. Keeping grating couplers, waveguides, and detectors as separate components with clearly defined ports allows flexible connection and independent simulation or optimization of each part. > This modular approach improves simulation accuracy by isolating the region of interest, enables automated layout generation and parameter sweeps, and makes it easy to reconfigure or replace sub-components, such as swapping a grating coupler without redesigning the detector. Clear port definitions also help to maintain unambiguous physical and simulation boundaries, simplifying both the design process and debugging. Now we add cladding using `gf.components.rectangle`. Here, we create a cladding with a width of 3 microns on layer (2, 0): ```python # Add SiO2 cladding for the waveguide clad_width = 3.0 clad_length = 10.0 # keep the same as the waveguide clad_layer = (2, 0) clad = gf.components.rectangle(size=(clad_length, clad_width), layer=clad_layer) ``` ```python # Combine the cladding and waveguide (c) c_with_cladding = gf.Component() ref_clad = c_with_cladding << clad ref_wg = c_with_cladding << c # Move the waveguide so its centerline is vertically centered within the cladding ref_wg.move(origin=(0, 0), destination=(0, clad_width / 2)) # The reference point (0, 0) of the waveguide is at its left center (centerline), # while for the rectangle it is at the bottom-left corner. c_with_cladding.plot() c_with_cladding.write_gds("straight_with_cladding.gds") ``` Now, using the `cross_section` function, we can create more complicated cross-sections in a more modular way. Below, we use the same method to generate a waveguide with cladding, but this time, the structure is defined via `cross_section` and passed directly to the `gf.components.straight` function. This approach is more flexible for future parameter scans or for adding more layers and process details. ```python # Create a cross-section with a Si core and SiO2 cladding xs = gf.cross_section.cross_section( width=0.5, # Core width layer=(1, 0), # Core layer (Si) sections=[ gf.cross_section.Section( width=3.0, # Cladding width offset=0, # Centered layer=(2, 0) # Cladding layer (SiO2) ) ] ) # Generate a straight waveguide with the above cross-section c_xs = gf.components.straight(length=10, cross_section=xs) c_xs.plot() c_xs.write_gds("straight_with_cross_section.gds") ``` With this approach, the geometric relationship between the core and cladding is always maintained by the cross-section definition, making it straightforward to adjust widths, layers, or add additional process layers as needed.