DOCUMENTATION

Get started.

Download a working layout and run your first prediction. Then adapt the example to your own GDS.

01 / YOUR FIRST PREDICTION

Run the Y-branch splitter.

  1. 1. Install the package Use Python 3.9 or later. Open a terminal and run python -m pip install --upgrade bamsolve. NumPy is installed with the package.
  2. 2. Get your key Enter your email in the key form. Copy the key shown on the page. The script will ask for it in the terminal.
  3. 3. Download two files Save ebeam_y_1550.gds and quickstart.py in the same folder. No GDS editor or generator is required.
  4. 4. Run the script Open that folder in your terminal and run python quickstart.py. Paste your key at the prompt and press Enter. The key is hidden while you enter it. Wait for the response; the script makes one prediction request.
  5. 5. Read the result The script prints the full S-matrix power ratios and saves ebeam_y_1550.s3p plus ebeam_y_1550_result.npz beside the GDS. The Y-branch has three ports, so res.S.shape is (1, 3, 3) at one wavelength.
  6. 6. Check the export (optional) Download read_result.py. Install scikit-rf, then use --check-touchstone as shown below. This independent file reader compares the exported S-matrix and frequencies with the saved arrays. It makes no API request.
# Run these commands in your terminal.
python -m pip install --upgrade bamsolve

# Open the folder with both downloaded files.
python quickstart.py

# Paste your key when the hidden prompt appears.
# The script saves:
#   ebeam_y_1550.s3p
#   ebeam_y_1550_result.npz

The sample is a silicon Y-branch about 15 µm long, with a 0.22 µm thickness. The request uses TE polarization at 1.55 µm.

Port 1 is opt1 at the left end. Ports 2 and 3 are opt2 and opt3 at the upper and lower right ends. abs(res.S[0, 1, 0])**2 and abs(res.S[0, 2, 0])**2 give the power ratios into the two arms.

The default API address is https://api.bamsolve.com. You can also set BAMSOLVE_API_KEY before running the script to use an existing key without a prompt.

Why use a Y-branch for this tutorial?

A 3D FDTD model must include the branch junction, both output arms, the surrounding cladding, and the waveguide thickness. A direct full three-port S-matrix calculation also needs a separate excitation at each port. This adds simulation volume and repeated runs compared with the simple straight-guide check. Runtime depends on mesh resolution, the stopping rule, and hardware. See the Meep introduction for background on FDTD grids and time steps.

02 / DOWNLOADS

Try another layout.

# Inspect the saved Y-branch result (the default).
python read_result.py

# Optional: check the exported S-matrix and frequencies.
python -m pip install scikit-rf
python read_result.py --check-touchstone

# Optional: save a field plot as a PNG.
python -m pip install matplotlib
python read_result.py --plot

# Optional: run the simpler straight-guide check.
python quickstart.py straight_10um.gds
python read_result.py straight_10um_result.npz

# Optional: rebuild the straight GDS locally.
python -m pip install gdstk
python make_straight.py

The optional straight guide is 10 µm × 0.5 µm. It produces an S array with shape (1, 2, 2) and a .s2p file. The plot reader uses |E|² / max(|E|²), so its colors show relative intensity.

03 / GDS LAYOUT

Prepare your own GDS.

The supplied examples use one silicon core layer. Start with this layout convention before you change the material or geometry.

  • Waveguide geometry — (1, 0) A pair means (layer, datatype). Draw the core on (1, 0) and map that pair to a Layer in Stack. The examples use micrometres and a 1 nm GDS precision. Use one core material and one vertical layer for this tutorial.
  • Port markers — one pair per port Put a short GDS path at each waveguide end, centred on the end face. Use (1, 10), (1, 11), then (1, 12). The generator uses simple_path=True so gdstk writes PATH records.
  • Name and select ports Put a text label such as opt1 at each marker, with the same layer and texttype. The supplied examples use opt1, opt2, and opt3. Pass the exact marker pair to pred() to select the input for the returned field.
  • Mark every external port Markers identify the ports used for the S-matrix and field selection. A marker is not a promise of zero reflection or an absorbing boundary condition.

EXAMPLE / 1×2 Y-BRANCH SPLITTER

Port 1: (1, 10) input port Waveguide: e.g. (1, 0) Port 2: (1, 11) Port 3: (1, 12) output ports

Diagram only. Download the GDS above for the actual geometry and markers.

04 / PYTHON API

The code inside the starter.

This basic request uses the downloaded Y-branch. Run it from the folder that contains the GDS.

  • 1. Stack Set the cladding index and core refractive index. z=(0.0, 0.22) gives the bottom and top in µm. The default sidewall angle is zero degrees.
  • 2. Device Call the stack with the GDS path. This combines the layer mapping and the layout.
  • 3. Predict Each input is (port_layer_pair, polarization, wavelength). The wavelength is in µm. Use "TE" or "TM"; request one polarization at a time for this example.
from getpass import getpass
from bamsolve import Layer, Stack, bamsolve, pred

bamsolve(api_key=getpass("API key: "))

stack = Stack(clad=1.444, layers={
    (1, 0): Layer(n=3.48, z=(0.0, 0.22)),
})
dev = stack("ebeam_y_1550.gds")
res = pred(dev, inputs={((1, 10), "TE", 1.55)})
res.export_s("ebeam_y_1550.s3p")

05 / OUTPUTS

Read fields and S-parameters.

  • Full S-matrix res.S is complex, with shape (wavelength, output_port, input_port). All input columns are calculated. The supplied examples use port order opt1, opt2 or opt1, opt2, opt3. Indices start at zero.
  • Power ratios abs(res.S[0, 1, 0])**2 gives transmission from port 1 to port 2 at the first wavelength. Diagonal entries give reflection at each port.
  • Field and coordinates res.E is a complex array with shape (len(res.y), len(res.x)). Coordinates are in µm. For the basic request, the field is for opt1 at 1.55 µm.
  • Multiple inputs or wavelengths For a wavelength sweep, pass a tuple such as (1.53, 1.55, 1.57). The S wavelength axis is in ascending wavelength order. The returned field uses the first input after sorting by port pair, then polarization; for a wavelength tuple it uses the middle entry. Request one input and one wavelength when you need an unambiguous field view.
  • Effective index and exports res.n_eff is the dimensionless effective index at each wavelength. res.export_s() saves Touchstone. Use .s2p for two ports or .s3p for three.
import numpy as np

print(res.S.shape)
print("Port 1 to port 2:", abs(res.S[0, 1, 0])**2)
print("Port 1 to port 3:", abs(res.S[0, 2, 0])**2)
print("Port 1 reflection:", abs(res.S[0, 0, 0])**2)
print("Field shape:", res.E.shape)
print("Effective index:", res.n_eff)

# Optional plot dependency:
# python -m pip install matplotlib
import matplotlib.pyplot as plt

plt.pcolormesh(res.x, res.y, np.abs(res.E)**2,
               shading="auto")
plt.xlabel("x (µm)")
plt.ylabel("y (µm)")
plt.axis("equal")
plt.show()

To inspect an earlier run without a new request, use read_result.py with the saved _result.npz file.