Workflow¶
mesh¶
lumi.mesh(path, component, layer_stack, materials, zmin, zmax)Writes .obj meshes of gdsfactory component extruded by layer_stack, clipped to [zmin, zmax], into simulation folder path. Call before setup.
setup¶
lumi.setup(path, sources, monitors, nres=6, wls=None, wl=None, f=None, fs=None, c0=None, targets=[], designs=[], approx_2D_mode=None, **kwargs)Writes simulation problem to folder path. Call mesh first, then solve.
Args:
wl and/or wls: center wavelength and wavelengths to compute results at, or
f and/or fs with c0: center frequency and frequencies, with speed of light c0 in your units eg 300 [mm GHz]. Results are then ordered by frequency
sources, monitors: from
source,monitor,gf_source,gf_monitorframes: from
plane_frame,box_frame,spherical_frame,points_frame,cage_framematerials: dict of name to
materialbackground: material name filling empty space
bbox: simulation box [[xmin, ymin, zmin], [xmax, ymax, zmax]]
boundaries: per axis “PML”, “PEC”, “PMC”, “periodic” or pair (min side, max side) eg (“PEC”, “PML”)
k_bloch: Bloch wavevector [kx, ky, kz] in rad per length unit on periodic axes, eg from
k_bloch. Fields pick up phase e^(i k L) across each period. Nonzero makes fields complex (2x memory)nres: grid points per wavelength in material. 6 is a good starting point for photonics; increase to check convergence
tmax: max simulation time [periods]. Optional with
stop_decay, except with time-domain monitors or inverse designstop_decay: stop early once field energy decays to this fraction. One of
tmax,stop_decayis requiredPML_decay: PML field attenuation, scalar or per axis
courant: time step relative to max stable
subpixel_smoothing: subpixel averaging of material boundaries
views: from
view, for movieshot_every: save movie frame every _ periods
full_fields: save full 3D field snapshots instead of only view slices, so
movie(path, views=...)can re-render new slicesdevice: “gpu” (default) or “cpu”
dtype: leave unset; chosen automatically. Pass “f32” or “f16” only to override
approx_2D_mode: 2D approximation
designs, targets, optimizer: inverse design, from
design,target,optimizer
solve¶
lumi.solve(path)Run simulation in folder path prepared by setup. Writes solution.json.
Runs on a Luminescent server if env LUMI_API is set (see remote_solve).
Runs the Julia source instead of the compiled binary if env LUMIDEV is set.
load¶
lumi.load(path, show=True)Load solution dict from path. Monitor results in sol[“monitors”][name], eg [“modes”][mode number][“+” or “-”] as array over wavelengths (or frequencies if setup with fs).
movie¶
lumi.movie(path, views=None, fps=None, src='frames')Show simulation movie in path, rendered by solve.
views (overrides views from setup) or fps re-render it from field snapshots, which cloud solves don’t keep.
Also re-renders if snapshots are newer than the movie.
src: “frames” for time snapshots, “history” for peak snapshot per optimization iteration.
view¶
lumi.view(field, name='', prop='n', x=None, y=None, z=None, field_color_intensity=1.0, show_grid=False, show_box=True, labels='auto', mirrors=[])Movie view: slices of field overlaid on material property prop, for setup(views=...).
Args:
field: field component eg “Ey”, “Hz”
name: movie file name, defaults to field and slice positions
prop: material property underneath eg “n”, “epsilon”
x, y, z: slice position along that axis, “half” for the simulation box center, or None for no slice. One panel per slice
field_color_intensity: scales field color saturation
show_grid: draw grid lines
show_box: draw simulation box outline
labels: “auto” to label sources and monitors, or dict of name to label
mirrors: reflect across symmetry boundaries for display eg [“z-”]
Materials¶
material¶
lumi.material(n=None, epsilon=None, mu=1, sigma=0, chi2=0, chi3=0, dispersion=[], placeholder=False)Define material properties in relative units
Args:
epsilon: relative permittivity
mu: relative permeability
sigma: conductivity (multiply by
377 * (characteristic wavelength in m)to convert from metric (S/m, 1 /(Ω m)) to relative units)chi2: Pockels second order nonlinear susceptibility
chi3: Kerr third order nonlinear susceptibility
dispersion: list of tuples [(gamma, omega, is_lorentzian)...] each defining a dispersion term.
is_lorentzian=Truefor Lorentzian,Falsefor Drude. We use Meep convention https://meep .readthedocs .io /en /latest /Materials / #material -dispersion and relative units. n: mesh density relative to vacuum, defaults to square root of relative permittivity
PEC_material¶
lumi.PEC_material(n)Perfect electric conductor material for modeling metals
placeholder_material¶
lumi.placeholder_material(n)placeholder material contributes to meshing but not to physical properties, eg used for design region
Sources & monitors¶
source¶
lumi.source(name, origin, basis=None, frame=None, dim=None, mirrored=False, wl=None, f=None, bandwidth=None, duration=None, modenums=[0])Modulated Gaussian pulse source with gradual spectral roll off at bandwidth limits. Becomes continuous wave if bandwidth=0.
Args:
name: should match a port name eg “o1”
origin: position [x, y, z], or coordinate along
dimforfaceframesbasis: rows local x, local y, outward normal. source injects bidirectionally (along both ±normal)
frame: name of
plane_frameorfaceholding mode profiledim: outward normal along axis ±1, ±2, ±3 (x, y, z) instead of
basismirrored: reflect frame and modes across local x=0, eg for port on opposite side of a symmetric frame
wl or f: wavelength or frequency, specify either (not both). f requires c0 in setup
bandwidth: in same units as above
modenums: list of mode numbers to excite
monitor¶
lumi.monitor(name, origin, basis=None, frame=None, dim=None, mirrored=False, t0=0, x=None, y=None, z=None, direction='+', layer=None)Monitor recording results of frame at origin in basis.
Args:
name: should match a port name eg “o1”. Unique among monitors
origin: position [x, y, z], or coordinate along
dimforfaceframesbasis: rows local x, local y, outward normal. “+” results propagate along normal, “-” against
frame: frame name
dim: outward normal along axis ±1, ±2, ±3 (x, y, z) instead of
basismirrored: reflect frame and modes across local x=0
t0: start recording time-domain signals at t0 [periods]
gf_source¶
lumi.gf_source(port, c, layer_stack, offset=0, name=None, **kwargs)source at gdsfactory port port of component c, offset along outward normal. name defaults to port name. kwargs go to source.
gf_monitor¶
lumi.gf_monitor(port, c, layer_stack, offset=0, name=None, **kwargs)monitor at gdsfactory port port of component c. name defaults to port name. kwargs go to monitor.
gaussian_mode¶
lumi.gaussian_mode(D, n, dx, wl, theta=0, half=None, Dlim=None)Tilted Gaussian beam mode for plane_frame(modes=...), eg fiber.
Args:
D: mode field diameter (1/e^2 intensity)
n: refractive index of medium
dx: sampling
wl: vacuum wavelength
theta: tilt angle [rad] in medium in local xz plane
half: “y+” for half frame y>=0 (symmetry plane at y=0)
Dlim: frame full width, default 1.5*D
Frames¶
plane_frame¶
lumi.plane_frame(name, start, stop, fs_mode_solver=[], wls_mode_solver=[], modes='auto', nmodes=1, metallic_boundaries=None, boundaries=('PML', 'PML'), time_domain=None, frequency_domain=None)Plane port frame between local start, stop (2 coords in 3D). Mode solutions at given frequencies or wavelengths; sources and monitors use (or interpolate) modes at closest wavelengths. Results: modes, flux, power. Records frequency-domain results by default, or time-domain signals if time_domain=True (or frequency_domain=False).
Args:
fs_mode_solver or wls_mode_solver: frequencies (requires c0 in setup) or wavelengths to solve modes at, specify one (not both)
modes: “auto” to solve, else precomputed fields eg [[{‘Ex’: np_array, ‘Hy’: ...}, ...], ...]
nmodes: number of modes to solve for
metallic_boundaries: PEC outlines for mode solver: layer names or frame edges “x-”, “x+”, “y-”, “y+”
points_frame¶
lumi.points_frame(name, points, sensor=None, time_domain=None, frequency_domain=None)Points in monitor basis. Records frequency-domain results by default, or time-domain signals if time_domain=True (or frequency_domain=False).
Args:
sensor: “voltage”: ∫E·dl along polyline
points. “current”: ∮H·dl around closed looppoints. None: raw fields.
box_frame¶
lumi.box_frame(name, start, stop, dr, time_domain=None, frequency_domain=None)Box volume frame between local start, stop (3 coords in 3D), sampled every dr (scalar or per axis). Results: fields in monitor basis. Records frequency-domain results by default, or time-domain signals if time_domain=True (or frequency_domain=False).
cage_frame¶
lumi.cage_frame(name, start, stop, dr, theta=3.141592653589793, phi=6.283185307179586, dtheta=np.float64(0.08726646259971647), dphi=np.float64(0.08726646259971647), time_domain=None, frequency_domain=None)Cage: closed surface of box between local start, stop (3D only), faces sampled every dr (scalar or per axis). Results: flux per face (outward), power, farfield intensity and directivity on (theta, phi) grid. theta, phi: max angle (range from 0) or [min, max]. Records frequency-domain results by default, or time-domain signals if time_domain=True (or frequency_domain=False).
spherical_frame¶
lumi.spherical_frame(name, r, theta=3.141592653589793, phi=6.283185307179586, dtheta=np.float64(0.08726646259971647), dphi=np.float64(0.08726646259971647), time_domain=None, frequency_domain=None)Sphere (circle in 2D) of radius r about monitor origin, in monitor basis. theta, phi: max angle (range from 0) or [min, max]. Results: flux (radial), power, and if closed (full theta, phi), farfield intensity and directivity on (theta, phi) grid. Records frequency-domain results by default, or time-domain signals if time_domain=True (or frequency_domain=False).
Inverse design¶
design¶
lumi.design(name, layer, lmin, fill_material, void_material, component, layer_stack, materials, symdims=[], repdims=[3], anchordims=[], dependent=False, topopt=True, contour_layer=None)Design region to be optimized
Args:
name: design name eg “d1”
layer: placeholder layer for design region
lmin: minimum feature size
fill_material: eg ‘Si’
void_material: eg ‘SiO2’
symdims: eg [“x”,“y”,“diagonal”]
component, layer_stack, materials: as in setup
repdims: eg [3] for planar design region extruded along z
anchordims: signed dims eg [-1, 2] whose design edges (x-, y+) are closed instead of open
topopt: allow topology change
contour_layer: optional layer whose polygons mask the design region; only pixels inside are optimized, rest keep initial geometry
target¶
lumi.target(src, dst, target, target_func='abs2', error_func='abs', weight=1, f=None, wl=None)src: source port and mode eg “o1@0-” (mode 0 incoming)
dst: destination port and mode eg “o2@0+” (mode 0 outgoing)
target: target value
target_func: applied to S parameter before comparing to target eg “abs2” for power
weight: weight of this target in overall loss function
f or wl: frequency or wavelength, specify one (not both)
error_func: error function `abs, identity, -, relu, relu-’
optimizer¶
lumi.optimizer(iters, stoploss, startloss=1, lowloss=None, highiter=None, momentum=0.7, contrast=0.7, init_dA=0.03, ckptat=None, gradckptat=None)Args:
iters: maximum number of optimization iterations
stoploss: stop optimization if loss goes below this value
startloss: initial loss estimate
lowloss: loss at which contrast reaches 1. defaults to 0.2 * stoploss + 0.8 * startloss
highiter: iteration at which contrast reaches 1. None ramps by loss only
momentum: optimizer momentum
contrast: initial binary contrast (0 to 1). slightly <1 enables topology change (new holes or islands). =1 freezes topology eg shape optimization. contrast automatically increases quadratically to 1 as loss decreases to
lowlossor by iterationhighiter, whichever firstinit_dA: fraction of design area changed by the first step. sets the initial step size
ckptat: save optimization checkpoint every _ iterations
gradckptat: gradient checkpointing
apply_design¶
lumi.apply_design(c0, sol)Replace design regions of component c0 with optimized designs from solution sol.
design_from_gds¶
lumi.design_from_gds(path, i=1)Import ith optimized design from path as gdsfactory component.
Utilities¶
straight¶
lumi.straight(length=10, width: float = 1, layer=(1, 0))Rectangular gdsfactory component with ports “o1” (west) and “o2” (east).
remote_solve¶
lumi.remote_solve(path, api=None, token=None, poll=3)Run simulation in folder path on a Luminescent server. Uploads inputs, streams the log, downloads results into path.
The server renders the movie; field snapshots are not downloaded.
api and token default to env LUMI_API and LUMI_TOKEN (or JUPYTERHUB_API_TOKEN in hosted notebooks).
Run from your own machine, a copy is also kept in your Lumi Colab home at ~/local/runs/.
load_sparams¶
lumi.load_sparams(sparams)Convert {“re”, “im”} dicts to complex values.
version¶
lumi.version()Installed luminescent python package version. Its X.Y must match the solver binary’s X.Y.0.