EME
Every section function below accepts a ports argument, which names, windows, or displaces the ports on either end of the section, in place of its default left and right ports. Sections are otherwise connected in the order they are declared. Use connect_ports to wire named ports explicitly instead, including into branching topologies. See Ports for the port model, the Port and Bounds classes, and make_angled_facet_port() for declaring an angled facet on a port. For a grating, grating_sections() gives the length of every section of a uniform, chirped or noisy grating.
- EME_settings
Declare global EME defaults that are inherited by sections created afterward. Each parameter left unspecified leaves the corresponding stored default unchanged. A section’s own
settingsargument at creation still overrides these globals. Sections created before this call are not affected.- Parameters:
apply_scattering (bool or list[float]) – whether interfacial scattering loss is automatically applied to the S-matrix, either for every wavelength (True), no wavelengths (False), or only the listed wavelengths, default: False
beta_interpolation (str) – either ‘uniform’ or ‘linear’ to specify how the propagation constant is interpolated between z-slices of a taper/gds section, default: ‘uniform’
junction_normalization (bool or str or dict) – controls how junction S-matrices are power-normalized. It takes either a single bool/’gain’ value applied to both junction kinds, or a dict with ‘inter_section’ and ‘intra_section’ keys, each accepting True (full SVD unitarization), False (raw, unnormalized), or ‘gain’ (clip singular values at 1 while keeping the raw lossy mode-matching), default: ‘gain’ for inter-section junctions and True for intra-section junctions. It applies to junctions with a plane-wave side (
pwd_section) or an angled facet. A junction between two mode-solved cross-sections conserves power by construction and is not normalized.overlap_variation (float) – threshold of mode-list overlap between z-slices used by the automatic z-slicing bisection for taper/gds sections, default: 0.01
minimum_z_step (float) – [nm] the minimum allowed z-step for the automatic z-slicing bisection, default: 1. When the largest junction error has not fallen by 20 % over three bisections, the bisection follows instead the power that the modes guided at both ends of the section lose at each junction, and if that stalls too it stops with a warning
snap_window (float) – the fraction of a slice’s length around its midpoint within which the automatic z-slicing bisects at a cross-section already solved elsewhere (for the same settings, mesh and wavelength) instead of at the midpoint, which saves a mode solve wherever two tapers or GDS sections share widths. 0 always bisects at the midpoint, default: 0.25
initial_slices (str) – how a taper or GDS section is sliced before the automatic z-slicing bisection refines it, either ‘auto’ (boundaries placed where the cross-section changes, from its rasterized refractive index: none along a straight run, evenly along a linear taper, densely inside a short fast feature, and at every corner of a GDS outline) or ‘single’ (one slice, the behavior before EMode 1.0.6). Refinement still runs afterward and decides the final slicing, so the choice moves results only within its tolerance and changes how many rounds it takes. A
warm_startinEMEtakes its slices from the previous solve instead, default: ‘auto’simulation_name (str) – simulation name, default: ‘emode’
A section’s own
settingsdictionary accepts the keys above (exceptsimulation_name), and five more that tune the slicing. They are rarely needed, andEME_settingsdoes not take them.schedule_samples: the number of positions along the section at which the refractive index is rasterized (no mode solve) to find where it changes, at least 2, default: 128schedule_change_per_slice: the relative change in the rasterized index that one initial slice spans, so a smaller value starts with more slices, default: 0.05schedule_max_slices: the largest number of initial slices, default: 64schedule_coarsen: how many times coarser than the profile’s mesh the index is rasterized, at least 1, default: 4slice_phase_limit: a slice over which the cross-section changes is kept shorter thanslice_phase_limit * wavelength / (2 n_max), wheren_maxis the largest effective index of its modes. Equal slices longer than aboutwavelength / (2 n_max)act as a grating and reflect in phase, which refinement cannot see. The initial slices are cut evenly under this limit, up toschedule_max_slices. Refinement then estimates how much power each guided mode loses to the steps’ in-phase reflections and conversions, and cuts a slice under the limit only where that power is significant, so a long, slow taper keeps aboutschedule_max_slicesslices. Between 0 and 1, or None to turn it off, default: 0.8
For example,
taper_section(..., settings={'schedule_change_per_slice': 0.02}). Initial slice boundaries closer together thanminimum_z_stepare merged.
- straight_section
Define a uniform-cross-section waveguide section for the EME solver. Sections are placed sequentially in the z-direction in the order they are declared (or updated, if
namealready exists).- Parameters:
name (str) – section name, default: an auto-generated number
profile (str) – name of the profile that defines the section’s cross-section
length (float) – [nm] the length of the section
offset (float or tuple[float, float]) – [nm] transverse displacement of this section relative to whatever its ports connect to. A single value is taken as the x-offset, default: (0, 0). Legacy: this is the same displacement as
Port’s ownoffsetapplied to every port of the section at once, and setting both on one section raises an error. Prefer declaringoffseton the specific port that sits off-axis.ports (list[Port] or None) – replace the section’s default
[Port('left', None, 'left'), Port('right', None, 'right')]on a per-side basis, where a supplied port replaces every existing port on the same side, and multiple ports may share a side. SeePort, default: None (keep existing/default ports)nonlinear (SHGProcess or SFGProcess or DFGProcess or PulsedProcess or False or None) – declare a \(\chi^{(2)}\) process on this section (EMode3D only), one of
SHGProcess(pump_wavelength=...),SFGProcess(pump_wavelength_1=..., pump_wavelength_2=...)orDFGProcess(pump_wavelength=..., signal_wavelength=...)fromemodeconnection. You name the process’s input wavelength(s), and the remaining one follows from energy conservation and is matched against the section’s own profile wavelengths. Quasi-phase matching is declared on the process withpoling_period[nm], plusduty_cycle(default: 0.5) andqpm_order(default: 1). Settinginverted=Trueinstead flips the local \(\chi^{(2)}\) sign for this section alone, the building block for poling assembled by hand from alternating sections. The two routes agree. Omittingnonlinear(or passingNone) when updating an existing section leaves the declared process in place, passing a new one replaces it, andnonlinear=Falseremoves it, so the section propagates linearly again. A pump must also be declared, seeexcitationinsettings, and the power-dependent result is read back withget('response'). The process also carriesz_samples(default: 100), the number of points at which the forward amplitudes are recorded along each slice of this section once the driven solve converges. Those reach the caller asget('response').power_vs_z(wavelength), which returns the pump or signal power against position from a single solve rather than one solve per length. Set it to 0 to skip the sampling. A pulse’s nonlinearity is declared instead with aPulsedProcess, see pulsed nonlinear propagation. Default: Nonesettings (dict or None) – per-section overrides of the
EME_settings, merged onto the current global EME settings (or onto the section’s existing settings, when updating), e.g.settings={'overlap_variation': 0.005}, default: Nonesimulation_name (str) – simulation name, default: ‘emode’
- pwd_section
Define a free space section, in which the field is expanded in plane waves (a plane-wave decomposition, PWD) over a uniform material, rather than in the guided modes of a cross-section. This is intended for gaps, facets, and free space propagation between waveguide sections. The junctions between a free space section and its neighbors are computed analytically instead of from a mode solve.
The basis is the set of plane-wave harmonics of the section window, with transverse wavevectors
kx = 2*pi*m/window_widthandky = 2*pi*n/window_height, each harmonic carrying both a TE and a TM polarization. At least one ofmax_order,max_kt, ornum_modesis required to truncate the basis. When more than one is given, they are applied in the ordermax_order,max_kt,num_modes.- Parameters:
name (str) – section name, default: an auto-generated number
length (float) – [nm] the length of the section
material (str or ~MaterialProperties or ~MaterialSpec) – the material filling the section, either a material name (from the material database) or a ~MaterialProperties or ~MaterialSpec object. It must be isotropic, default: “Vacuum”
profile (str) – name of the profile that supplies the default window and the wavelength(s) of the section, default: ‘_default’
window (tuple[float, float] or None) – [nm] the (width, height) of the plane-wave window, which overrides the window of
profile, default: None (use thewindow_widthandwindow_heightofprofile)offset (tuple[float, float]) – [nm] transverse displacement of the window’s origin, which is its horizontal center and bottom edge, default: (0, 0)
max_order (tuple[int, int] or None) – the largest harmonic order to keep in the x- and y-directions, so that
|m| <= max_order[0]and|n| <= max_order[1], default: Nonemax_kt (float) – [1/nm] the largest transverse wavevector magnitude to keep, default: None
num_modes (int) – the largest number of modes to keep, counting both polarizations of each harmonic, and applied after
max_orderandmax_kt. The basis always keeps a harmonic together with its opposite-direction pair, so the resulting count can land slightly below the requested value. Default: Noneports (list[Port] or None) – replace the section’s default
[Port('left', None, 'left'), Port('right', None, 'right')]on a per-side basis, where a supplied port replaces every existing port on the same side, and multiple ports may share a side. SeePort, default: None (keep existing/default ports)settings (dict or None) – per-section overrides of the
EME_settings, default: Nonesimulation_name (str) – simulation name, default: ‘emode’
Note
A junction with a free space section matches the two continuity conditions (for E and for H) against the modes of the side the light arrives from. When the other side has fewer modes, the junction cannot represent every incident field, and some incident modes leave it with almost none of their power: they are dropped by the truncated basis, not attenuated by any physics. EMode warns when an incident mode keeps less than 1 % of its power, naming the dropped modes and the reflected plus transmitted power over all of the incident modes. Raise the mode count on the side with fewer modes,
num_modesof the waveguide section ormax_order,max_ktornum_modesof the free space section.Note
The reflection of a confined mode at a facet into free space is not the modal Fresnel value
((n_eff - n) / (n_eff + n))^2. That formula gives the free space the admittance of a single plane wave at normal incidence. A mode confined to a fraction of a wavelength is a spread of plane waves, and those at an angle see a different admittance: smaller for the field component normal to their plane of incidence, larger for the one in it. A quasi-TE mode therefore reflects more than its modal Fresnel value and a quasi-TM mode less, more so the tighter the confinement. A 2640 x 816 nm Si guide meeting SiO2 reflects 0.216 of its quasi-TE fundamental, 1.35 times its modal Fresnel value of 0.160, and an independent solve with an empty section in place of the free space agrees within 1.4 %. Give the waveguide section periodic walls (boundary_condition='PP') and the free space section the same window, so that both describe the same far side. Walls on a section that stands in for free space raise the reflection when they are close to the guide (by 35 % with walls 1 µm from that guide’s core).
- taper_section
Define a section that linearly interpolates its cross-section between two profiles for the EME solver, automatically slicing the z-direction to track the mode evolution.
- Parameters:
name (str) – section name, default: an auto-generated number
profile (str) – name of the profile that defines the section beginning
profile_end (str) – name of the profile that defines the section ending
length (float) – [nm] the length of the section
ports (list[Port] or None) – replace the section’s default
[Port('left', None, 'left'), Port('right', None, 'right')]on a per-side basis, where a supplied port replaces every existing port on the same side, and multiple ports may share a side. SeePort, default: None (keep existing/default ports)nonlinear (SHGProcess or SFGProcess or DFGProcess or PulsedProcess or False or None) – declare a \(\chi^{(2)}\) process on this section (EMode3D only), one of
SHGProcess(pump_wavelength=...),SFGProcess(pump_wavelength_1=..., pump_wavelength_2=...)orDFGProcess(pump_wavelength=..., signal_wavelength=...)fromemodeconnection. You name the process’s input wavelength(s), and the remaining one follows from energy conservation and is matched against the section’s own profile wavelengths. Quasi-phase matching is declared on the process withpoling_period[nm], plusduty_cycle(default: 0.5) andqpm_order(default: 1). Settinginverted=Trueinstead flips the local \(\chi^{(2)}\) sign for this section alone, the building block for poling assembled by hand from alternating sections. The two routes agree. Omittingnonlinear(or passingNone) when updating an existing section leaves the declared process in place, passing a new one replaces it, andnonlinear=Falseremoves it, so the section propagates linearly again. A pump must also be declared, seeexcitationinsettings, and the power-dependent result is read back withget('response'). The process also carriesz_samples(default: 100), the number of points at which the forward amplitudes are recorded along each slice of this section once the driven solve converges. Those reach the caller asget('response').power_vs_z(wavelength), which returns the pump or signal power against position from a single solve rather than one solve per length. Set it to 0 to skip the sampling. A pulse’s nonlinearity is declared instead with aPulsedProcess, see pulsed nonlinear propagation. Default: Nonesettings (dict or None) – per-section overrides of the
EME_settings(notablyoverlap_variationandminimum_z_step, which control the automatic z-slicing), default: Nonesimulation_name (str) – simulation name, default: ‘emode’
- bend_section
Define a bend for the EME solver: the cross-section of
profileswept along a curve. The bend is placed in the layout like any other section, and sections declared after it continue from its end, turned by the bend’s angle.The curve is a circular arc (
radiusandsweep_angle), or a curve whose radius varies along its length, which avoids the abrupt change of curvature where a circular bend meets a straight or where an S-bend reverses. A tuple of radii withsweep_anglegives a clothoid, whose curvature changes linearly with arc length, andinfstands for a straight end, soradius=(inf, 5000)eases a straight into a 5 um bend.euler=dict(angle=..., min_radius=...)gives a symmetric Euler bend, its curvature rising linearly from zero to1 / min_radiusat its middle and back to zero, of length2 |angle| min_radius.curvaturewithlengthgives any other profile. A bend whose radius varies is sliced along its length like a taper, each slice solved at its own radius, and refined byEME. Its layout follows the curve.An anisotropic crystal is fixed in the chip, so the guide sees it turn along the bend. When a material is anisotropic in the plane of the chip (x-cut lithium niobate, for example), the bend is sliced along its heading and refined like a taper, and every section placed after a turn sees the crystal turned with it. A circular bend of an isotropic material, or of a crystal whose optic axis is vertical (z-cut thin film), is a single slice and a single mode solve. A
copy_sectionreuses its source’s S-matrix, so it raises an error when its own placement would show the crystal differently, and asks for the copy to be declared as its own section.A bend has no mirror symmetry about x, so an x symmetry wall in the profile’s
boundary_condition(such as ‘0S’ or ‘SA’) is replaced by ‘0’ with a warning, and ‘TE’ and ‘TM’ keep only the vertical fold. In a circuit that also has straight sections, the x fold then applies to none of them (seeEME). Updating an existing bend changes only the arguments given.- Parameters:
name (str) – section name, default: an auto-generated number
profile (str) – name of the profile that defines the cross-section
radius (float or list[float]) – [nm] the bend radius, measured to the origin of the profile’s x axis, must be positive. A list or tuple of radii, equally spaced in arc length with the curvature linear between them, gives a bend whose radius varies,
inffor straight. A new bend needsradiusandsweep_angle,euler, orcurvatureandlengthsweep_angle (float) – [rad] the angle the bend turns through, positive toward +x and negative toward -x, not zero. With a list of radii it sets the bend’s length
euler (dict or None) – a symmetric Euler bend,
dict(angle=..., min_radius=...), withanglein radians (positive toward +x) andmin_radiusin nm, default: Nonecurvature (list[float] or None) – [1/nm] the signed curvature (positive toward +x) at equally spaced points along the bend, from start to end, linear between them, at least two values. A change of sign gives an S-bend, default: None
length (float) – [nm] the arc length of a bend given by
curvature, default: Nonemethod (str) – how each slice is solved, either ‘cylindrical’ (the bend in cylindrical coordinates, as
bend_radiusinsettings) or ‘TO’ (transformation optics, seebend_methodinsettings), default: ‘cylindrical’ports (list[Port] or None) – replace the section’s default
[Port('left', None, 'left'), Port('right', None, 'right')]on a per-side basis, where a supplied port replaces every existing port on the same side, and multiple ports may share a side. SeePort, default: None (keep existing/default ports)settings (dict or None) – per-section overrides of the
EME_settings(notablyoverlap_variationandminimum_z_step, which control the automatic z-slicing), default: Nonesimulation_name (str) – simulation name, default: ‘emode’
- gds_section
Define a section whose cross-section varies along z according to a mask imported from a GDS file, for more complex geometries defined with third-party layout tools.
- Parameters:
name (str) – section name, default: an auto-generated number
profile (str) – name of the profile that defines the section’s cross-section outside of the GDS mask
gds_path (str) – path to the GDS file used to mask the section
layer_map (dict[str, int]) – mapping of profile shape names to GDS layer numbers, used to determine which shapes in
profileare masked by which GDS layerlength (float) – [nm] the length of the section, default: derived from the GDS bounding box
cell_index (int or str) – the cell index (or name) in the specified GDS file, default: 0
scale (float) – unit scale factor applied to the GDS coordinates (e.g. use 1000 if the GDS file is drawn in microns but the simulation is in nanometers), default: 1
port_poses (dict) – explicit port positions/orientations at the section boundaries, default: derived from the GDS bounding box (left port at w=0, right port at w=length)
heal (bool) – whether to heal small gaps/self-intersections in the imported GDS polygons before meshing, default: True
grow (float) – amount to grow imported GDS polygons by, to close small gaps, default: 1e-3
nonlinear (PulsedProcess or False or None) – declare a pulse’s nonlinearity on this section as a
PulsedProcess(see pulsed nonlinear propagation),Falseto remove one. The CW \(\chi^{(2)}\) processes are not available on a GDS section. Default: Noneports (list[Port] or None) – replace the section’s default
[Port('left', None, 'left'), Port('right', None, 'right')]on a per-side basis, where a supplied port replaces every existing port on the same side, and multiple ports may share a side. SeePort, default: None (keep existing/default ports)settings (dict or None) – per-section overrides of the
EME_settings, default: Nonesimulation_name (str) – simulation name, default: ‘emode’
Note
Once sections are declared, call plot() with plane='z-x' or plane='z-y' to preview a geometry-only ‘Outline’ of the section layout before running EME.
- copy_section
Place a second instance of an already-declared section in the chain, reusing its already-computed S-matrix instead of re-solving it.
- Parameters:
name (str) – section name, default: an auto-generated number
section_name (str) – name of the existing section to copy
mirror (bool) – whether to reverse the placement along the propagation direction (swapping the left/right ports), default: False
port_swap (dict) – explicit port-name mapping to use instead of the automatically computed left/right swap when
mirroris True, default: Noneports (list[Port] or None) – relabel/window this copy’s own left/right boundary, with the same semantics as any other section’s
ports, independent ofport_swapand of the source section’s own ports. SeePort, default: None (keep existing/default ports)settings (dict or None) – per-section overrides of the
EME_settings, default: Nonesimulation_name (str) – simulation name, default: ‘emode’
- connect_ports
Override the default left/right adjacency wiring between named ports declared with the
portsargument of any section function.Connecting two ports also pins their coordinate systems together: the two ports’ origins (the horizontal center and bottom edge of each cross-section) are made to coincide, so the connection is what positions one section relative to the other. Use
Port’soffsetto displace a section off that shared origin, and itswindowto choose which part of a wider cross-section the port exposes. The first section you declare defines the global frame that plots are drawn in.- Parameters:
pairs (list[tuple[str, str]] or list[tuple[str, str, JunctionOverride]]) – a list of
('<section_name>.<port_name>', '<section_name>.<port_name>')pairs to connect, e.g.[('a.right', 'b.left'), ('c.right', 'd.left')]. A port can only have one connection, so declaring a new connection for a port that already had one supersedes it. Names are resolved against the actual declared sections/ports atEMEbuild time. An entry may carry an optional third element, aJunctionOverride, configuring the junction that connection forms, e.g.[('a.right', 'b.left', JunctionOverride(junction_normalization=False))].simulation_name (str) – simulation name, default: ‘emode’
- class JunctionOverride
Settings for a single junction, passed as the optional third element of a
connect_portsentry. Every parameter left unspecified inherits the value the junction’s sections resolved, so setting one does not disturb the others.These settings belong to the connection rather than to either port because each one describes the interface between the two sections, not one side of it: which algebra joins their mode sets and how the resulting scattering matrix is normalized.
Only an explicitly connected junction can carry these. A junction formed by the default left/right adjacency has nowhere to declare them, so name that pair in
connect_portsto configure it, which supersedes the adjacency. The internal junctions of a taper or GDS section’s automatic z-slicing are controlled by that section’ssettingsinstead.- Parameters:
junction_normalization (bool or str or None) – how this junction’s scattering matrix is power-normalized, one of True (full SVD unitarization), False (raw, unnormalized), or ‘gain’ (clip singular values at 1 while keeping the raw lossy mode-matching), for a junction with a plane-wave side or an angled facet, default: None (inherit)
- EME
Calculate the complete scattering matrix of all defined sections using the eigenmode expansion method (EME). Before solving anything it checks the layout (see
check_layout) and raises an error when two sections overlap or a loop of connected sections misses closing (its two ports more thanminimum_z_stepapart, or more than 1e-6 rad from facing each other), and warns when a section’s outline crosses itself or a section is reached by no connection.A
boundary_conditionof ‘TE’, ‘TM’, ‘TE-h’, ‘TE-v’, ‘TM-h’ or ‘TM-v’ folds a cross-section only about a middle it is mirror symmetric about (seesettings). In a circuit, a fold applies only when every section is symmetric about it, because a folded section has no modes of the other parity, and where it meets an unfolded section the power those modes would carry is lost. When some sections fold about a middle and others cannot,EME()warns and solves the circuit again with that fold taken out of every section. Set a boundary condition without it (for example ‘TE-v’ instead of ‘TE’ for a circuit with offset or bent guides) to solve once.- Parameters:
warm_start (bool) – whether to seed each taper/gds section’s automatic z-slice refinement from the previously solved chain (when available), instead of re-refining from scratch, default: False
simulation_name (str) – simulation name, default: ‘emode’
- check_layout
Check the layout of the declared sections without solving. Every section is placed where its connections put it and drawn top down from its shapes that do not span the window. Returns a
LayoutReportwithoverlaps(pairs of sections whose outlines overlap, as(section, section, area)with the area in nm2, where sections that only share a port edge do not overlap),self_intersecting(sections whose own outline crosses itself, such as a bend swept past a full turn),closures(for each connection that closes a loop, how far apart its two ports are in nm and how far from facing each other in radians), andunplaced(sections no connection reaches, which are placed after the section declared before them).max_closure()returns the largest closure distance and angle, or zeros without a loop.plot(view='layout')draws the same layout.LayoutReportis defined inemodeconnection.- Parameters:
simulation_name (str) – simulation name, default: ‘emode’
- chi2_spectrum
Conversion spectrum of a \(\chi^{(2)}\) section, solved sparsely in wavelength (EMode3D only). Returns the signal power out over the pump power in at every wavelength in
values.A nonlinear spectrum oscillates with the phase mismatch, so it cannot be interpolated. At any useful resolution it has to be evaluated point by point. What can be interpolated is what the coupled-mode equations consume: the coupling and the propagation constants, which vary smoothly with wavelength. So the modes are solved at a handful of wavelengths chosen by how fast the mode list is actually moving, and the response is then evaluated at every requested wavelength from interpolated coupling. Against a directly solved 13-point spectrum across a phase-matching peak, five solves reproduce every point to four decimals, sidelobes included.
Quasi-phase matching is included: the grating enters as a wavevector shift and a Fourier coefficient built from
poling_period,duty_cycleandqpm_order, none of which depend on wavelength, so a poled section keeps its exact grating while its phase mismatch moves with the interpolated propagation constants.Requires a chain with a declared \(\chi^{(2)}\) section (see
nonlinearonstraight_section/taper_section) and a declared pump (excitationinsettings).- Parameters:
values (list or array) – pump wavelengths [nm] to report at (the signal wavelength follows from the declared process)
section (str) – which nonlinear section to scan, default: the only one declared
tolerance (float) – the largest mode-list change tolerated between adjacent solves, default: 1e-3
minimum_step (float) – [nm] the smallest wavelength gap the sampler will bisect into, default: the output spacing, since resolving finer than you asked to see cannot change the reported curve
initial_points (int) – solves to place before any bisection, default: 5
power (float) – [W] pump power, default: the declared excitation’s
simulation_name (str) – simulation name, default: ‘emode’
Returns a dictionary with
values,conversion(signal out over pump in),solved_wavelengths(where the solver actually ran), andunconverged(the intervals, if any, that the sampler could not resolve totolerancebefore reachingminimum_step).
- free_space_field
Declare, or update, a free-space field: a Gaussian, Hermite-Gauss or Laguerre-Gauss beam, or a combination of the port’s own modes, launched into a port of the chain. This is an excitation, not a section. It does not appear in the scattering matrix or in the layout.
After
EME,plot(excitation=name)(or the plot window’s Mode menu,'<name> (free space)') renders the field the beam launches, projected onto the target port’s modes with the same pairing the junctions use. Re-declaring an existingnameupdates only the arguments you give.- Parameters:
name (str) – free-space field name, default: the next number
port (str) – the external port the beam enters, either a bare side
'left'(default) or'right', or a qualified'<section>.<port>'name. The beam travels inbound from that port.waist (float or tuple[float, float]) – [nm] the 1/e field radius \(w_0\) in \(\exp(-r^2/w_0^2)\) at the beam’s waist, required when declaring a new Gaussian beam. A pair
(w_x, w_y)declares an elliptical beam, \(\exp(-x^2/w_x^2 - y^2/w_y^2)\) at its waistwaist_definition (str) – how
waistis measured:'1/e2_radius'is \(w_0\) above, the radius where the intensity falls to \(1/e^2\),'fwhm'the full width at half maximum of the intensity (\(w_0 = \mathrm{FWHM}/\sqrt{2 \ln 2}\)), and'mfd'the mode field diameter \(2 w_0\), the fiber convention. The beam stores \(w_0\), and a pair converts each axis. Default:'1/e2_radius'center (tuple[float, float]) – [nm] beam center
(x, y)in the port’s cross-section coordinates, default: (0, 0)tilt (tuple[float, float]) – [degrees]
(theta_x, theta_y), where a positivetheta_xsteers the beam toward +x. This is the angle inside the medium the beam travels through, default: (0, 0)component (str) – the one transverse E component the beam carries,
'Ex'(default) or'Ey'. Givecomponentorpolarization, not bothpolarization (tuple[float, float] or tuple[float, float, float] or None) – the beam on both transverse E components,
(a_x, a_y)or(a_x, a_y, delta): \(E_x\) carries \(a_x\) and \(E_y\) carries \(a_y e^{j\delta}\), withdeltain degrees (default 0). The pair is scaled so that \(|a_x|^2 + |a_y|^2 = 1\), soamplitudekeeps its meaning, and at least one of \(a_x\) and \(a_y\) must be nonzero.(1, 1, 90)is circular polarization, and other values give linear or elliptical polarization. It replacescomponent. Default: None (the beam oncomponentalone)envelope (str) – the beam’s transverse shape,
'gaussian','hermite_gauss'or'laguerre_gauss'. Each order is normalized to the power of the Gaussian of the same waist and amplitude, and order (0, 0) is the Gaussian. A Hermite-Gauss beam is separable, so it takes a pairwaistorwaist_position. A Laguerre-Gauss beam is circular, so it takes onewaistand onewaist_position, and a pair raises an error. Default:'gaussian'order (tuple[int, int]) – the beam’s order,
(m, n)of a Hermite-Gauss beam (\(H_m\) along x and \(H_n\) along y, both at least 0) or(p, l)of a Laguerre-Gauss beam (the radial index \(p \ge 0\) and the azimuthal index \(l\), which may be negative, with the phase \(e^{j l \phi}\)). Away from the waist the beam carries \(m + n + 1\) times the Gaussian’s Gouy phase for Hermite-Gauss, and \(2p + |l| + 1\) times it for Laguerre-Gauss. Default: (0, 0)amplitude (float) – peak field value at the waist, default: 1
wavelength (float) – [nm], default: None (each port’s own wavelength)
waist_position (float or tuple[float, float]) – [nm] the distance from the port to the beam’s waist, along the direction the beam travels. A positive value focuses the beam inside the chain, a negative one puts the waist behind the port (a diverging beam). The launched beam carries the wavefront curvature and Gouy phase of that distance, with the Rayleigh range \(z_R = \pi n w_0^2/\lambda\) of the port’s background index \(n\). A pair
(z_x, z_y)puts the waist along x and along y at different distances (an astigmatic beam). With a pair inwaistorwaist_position, each axis has its own Rayleigh range, wavefront curvature and half of the Gouy phase, and the beam’s power does not depend on either distance. Default: 0 (the waist on the port)phase (float) – [radians] global phase of the launched field, default: 0
modes (list[int]) – launch a combination of the target port’s own modes instead of a beam: their indices. Giving a beam’s
namea list ofmodes(or a mode combination’snameawaist) replaces it with the other kindpowers (list[float]) – one power per entry of
modes, default: 1 each. Each mode is launched with the amplitude \(\sqrt{P}\,e^{j\phi}\), as aSourceisphases (list[float]) – [radians] one phase per entry of
modes, default: 0 eachsimulation_name (str) – simulation name, default: ‘emode’
- free_space_field_diagnostics
How much of a declared free-space field’s power the target port’s modal basis actually captures, after
EMEhas solved the chain. The solver already warns when this falls below 90%. This returns it as a value a script can check or plot instead of parsing a log line.A low captured fraction means the port’s modes cannot represent the beam. Raise that section’s
num_modes, or widen its window, before trusting a coupling number computed from it.- Parameters:
name (str) – the free-space field to diagnose
wavelength (float) – [nm] which of a multi-wavelength chain’s ports to diagnose, default: None (the lowest wavelength present)
simulation_name (str) – simulation name, default: ‘emode’
Returns a
FreeSpaceProjectionwithcaptured_fraction, its complementdropped_fraction, the resolvedportandwavelength, and the launch basis’snum_modes.
- plot_S_matrix
Colormap plot of the transmission or reflection component of the EME scattering matrix.
- Parameters:
input (int or str) – input field (first number of the scattering matrix identifier), default: 0
output (int or str) – output field (second number of the scattering matrix identifier), default: 1
plot_function (str or None) – specify the function to apply to the plot data (‘abs^2’, ‘angle’, ‘real’, ‘imag’), default: ‘abs^2’
file_name (str) – if specified, forces the function to save a file with the given parameters and will not display the interactive plot, file is saved under a directory called EM_figures, default: None
file_type (str) – file type for saving a plot, ‘pdf’ or ‘png’, default: ‘’ (no extension is added to
file_nameunless a file type is given)simulation_name (str) – simulation name, default: ‘emode’
Monitors
A monitor is a plane inside the chain on which the solved field is sampled after EME. It is output only: it is not a port, does not enter the scattering matrix and does not change the solve, so monitors can be added, moved or removed without solving again. The plane runs across the full window in x and is tilted about x, so it can sample the light a grating coupler radiates upward. monitor_field returns the field on it, and monitor_coupling its coupling to a tilted Gaussian beam, such as the mode of a fiber above a grating. plot() draws each monitor’s plane on the ‘z-y’ panel, and sweep(result='monitor_coupling') sweeps the coupling (see sweep). The ‘EME: Grating Coupler’ example uses all three.
- monitor
Declare a monitor. Declaring the same name again replaces it.
- Parameters:
name (str) – the monitor’s name
w (float) – [nm] the position along the chain, from its left port, that the plane passes through
y (float) – [nm] the height that the plane passes through at
w. An untilted plane must lie inside the window, between 0 andwindow_heightangle (float) – [degrees] the tilt of the plane about x from horizontal, strictly between -90 and 90, where a positive angle tips the far end of the plane up, default: 0
length (float or None) – [nm] the extent along the plane, centered on (
w,y), default: None (as far as the chain and the window allow)resolution (float or None) – [nm] the sampling step along the plane, default: None (the window’s
x_resolution)simulation_name (str) – simulation name, default: ‘emode’
- monitor_field
The field on a monitor’s plane after
EME, for 1 W launched in one mode of one port.- Parameters:
name (str) – the monitor’s name
port (str) – the external port the chain is excited from, default: ‘left’
mode (int) – the launched mode, default: 0
wavelength (float or None) – [nm] which of a multi-wavelength chain’s wavelengths to use, the nearest one present, default: None (the chain’s first)
simulation_name (str) – simulation name, default: ‘emode’
Returns a
PlaneFieldwithfields, a dictionary of the six components (‘Ex’, ‘Ey’, ‘Ez’, ‘Hx’, ‘Hy’, ‘Hz’) on the plane, each a complex array of shape (len(x), len(s)), wherex[nm] runs across the plane ands[nm] along it, at chain positionswand heightsy[nm].Snis the time-averaged Poynting flux through the plane (positive along its upward normal),power_through_plane[W] its integral, andpower_inthe 1 W launched, sopower_through_planeis also the fraction of the launched power that crosses the plane.
- monitor_coupling
The coupling between a launched waveguide mode and a Gaussian beam through a monitor’s plane, after
EME. It is the fraction of the launched power crossing the plane times the normalized overlap of the field’spolarizationcomponent with the beam. By reciprocity the same number is the coupling from the beam into the launched mode, which is the figure a grating coupler is designed for. Only the overlap is computed, so trying other beams costs no solve.- Parameters:
name (str) – the monitor’s name
mode_field_diameter (float) – [nm] the beam’s mode field diameter, for example 10.4e3 for SMF-28 at 1550 nm
angle (float) – [degrees] the beam’s angle from the plane’s normal, positive toward +s (along the chain), default: 0
center (tuple[float, float] or None) – [nm] the beam’s center (x, s) on the plane, default: None (centered on the plane)
index (float or None) – the refractive index of the medium the beam travels in, default: None (the profile’s background material)
polarization (str) – the field component the beam couples to, ‘x’, ‘y’, or ‘s’ (along the plane), default: ‘x’
port (str) – the launching port, default: ‘left’
mode (int) – the launched mode, default: 0
wavelength (float or None) – [nm] which of a multi-wavelength chain’s wavelengths to use, default: None (the chain’s first)
simulation_name (str) – simulation name, default: ‘emode’
Returns a
BeamCouplingwithcoupling, its two factorspower_fractionandoverlap, and the beam it was computed for (mode_field_diameter,center,angle,index,polarization) atwavelength.
Pulsed nonlinear propagation
A femtosecond pulse is declared as the excitation, settings(excitation=PulsedSource(...)), and a section’s nonlinearity with nonlinear=PulsedProcess(...) on straight_section, taper_section or gds_section (EMode3D only). EME refines the chain at the pulse’s center wavelength, solves each distinct cross-section at dispersion_samples wavelengths across the pulse’s band, and propagates the pulse forward through every slice and junction with \(\chi^{(2)}\), Kerr (\(\chi^{(3)}\)), Raman and two-photon absorption, three- and four-photon absorption when asked for, and the free carriers that absorption makes. Reflections and power scattered into modes that are not tracked are discarded and reported, with a warning where that is not safe. The classes below are imported from emodeconnection.
The nonlinear coefficients come from the materials: \(\chi^{(2)}\) from the material’s \(d\) tensor, \(\chi^{(3)}\) from its nonlinear index \(n_2\) as \(\chi^{(3)} = \tfrac{4}{3}\varepsilon_0 c n^2 n_2\), the Raman response from the material that holds most of the Kerr overlap, and N-photon absorption from its coefficients, \(\beta_\mathrm{TPA}\) for two photons and \(\beta_3\) and \(\beta_4\) for three and four, each active only where N photons carry more than the material’s bandgap. In the material database, SiO2, SiN, Si, Diamond, LN and LN_MgO carry \(n_2\) (Air and Vacuum carry an \(n_2\) of zero), SiO2 (Blow and Wood) and LN/LN_MgO (four A1(TO) lines, Bache and Schiek) a Raman response, Si, GaAs, AlGaAs, Diamond, LN and LN_MgO a two-photon coefficient, Si, GaAs, LN and LN_MgO a three-photon coefficient, and Si a free-carrier model (Soref and Bennett), each with its reference in property_refs. A material of your own takes the same through MaterialProperties(n=..., n2=..., raman=(fraction, [(weight, position, half_width), ...]), tpa=..., beta_3=..., beta_4=..., bandgap=...), with \(n_2\) in m2/W, the Raman line positions and half widths in cm-1, \(\beta_\mathrm{TPA}\) in m/W, \(\beta_3\) in m3/W2, \(\beta_4\) in m5/W3 and the bandgap in eV. PulsedProcess(chi3=True) raises an error naming a material that has no \(n_2\).
- class PulsedSource
A pulse launched into one port of the circuit, for
settings(excitation=...).- Parameters:
center_wavelength (float) – [nm] the carrier wavelength, inside
wavelength_rangeduration (float) – [fs] the intensity FWHM, required except for
shape='cw'andshape='measured'energy (float) – [pJ] the pulse energy, give exactly one of
energyandpeak_power(a measured pulse is scaled to either, as an analytic one is)peak_power (float) – [W] the peak power
port (str) – the launch port, default: ‘left’
mode (int or dict) – the tracked mode that carries the pulse, or a dictionary
{mode: amplitude}of complex amplitudes that splits it between tracked modes (normalized, so only their ratios matter), default: 0shape (str) – ‘sech’, ‘gaussian’, ‘cw’ (a continuous wave of
peak_poweratcenter_wavelength, with nodurationorenergy), or ‘measured’ (the pulse ofmeasurement, with nodurationorchirp), default: ‘sech’chirp (float) – the chirp \(C\) of \(\exp(j C t^2 / 2 T_0^2)\), where a positive value raises the instantaneous frequency across the pulse, default: 0
measurement (PulseMeasurement or None) – a measured pulse for
shape='measured', seePulseMeasurement. A measured spectrum is launched at its own wavelengths, andcenter_wavelengthstays the wavelength at which the circuit is refined. A measured temporal trace is centered oncenter_wavelength. Default: Nonerepetition_rate (float) – [Hz] for average powers, default: None
wavelength_range (tuple[float, float]) – [nm] the span of the frequency grid, default: (450, 3500)
num_points (int) – frequency points, even and at least 16, which with
wavelength_rangeset the time window (the number of points over the frequency span, 28 ps at the defaults), default: 16384alias (int) – oversampling of the real-field products, 1, 2 or 3 (2 suffices for \(\chi^{(2)}\), 3 for \(\chi^{(3)}\)), default: 2
- class PulseMeasurement
A measured pulse, for
PulsedSource(shape='measured', measurement=...): a sampled spectrum (as from a spectrometer, often with a phase retrieved by FROG or SPIDER) or a sampled temporal trace. Give exactly one ofwavelengthandtime.The samples are never launched as they are.
settingsfits them first, so noise and sparse sampling do not reach the propagation, and refuses the source with an error when the fit is not good enough. The fit’s quality is 1 minus its normalized residual: the \(R^2\) of the intensity, less the intensity-weighted mean of \(1 - \cos\) of the phase error when a phase is given. Belowmin_fit_qualitythe error states the quality reached, the model and where the residual is largest, so you can choose another model, clean the data, or lowermin_fit_qualityknowingly. The accepted pulse is resampled onto the frequency grid, centered in the time window and scaled to the source’senergyorpeak_power. The fit is reported on the result asget('pulse_response').measured_fit, with itsmodel,quality,fwhm[fs],center_wavelength[nm],gdd[fs2],tod[fs3],chirp(for ‘sech’ and ‘gaussian’),transform_limited,energy_outside(the fraction of the energy cut by the window),residual_peakandbackground(the constant background subtracted, as a fraction of the samples’ peak).Data that stops while the pulse is still bright (above 5 % of its peak), or whose pulse lies mostly outside the source’s
wavelength_range, is refused. A spectrometer’s dark counts or stray light put a constant background under the whole trace, which reads as a pulse that never reaches zero: givebackgroundto subtract it before the fit and this check. Data that reaches pastwavelength_range(or past the time window) is cut with a smooth window, with a warning giving the fraction of the energy outside.- Parameters:
wavelength (list[float] or numpy array or None) – [nm] the wavelengths of a measured spectrum
time (list[float] or numpy array or None) – [fs] the times of a measured temporal trace
intensity (list[float] or numpy array) – the intensity at each sample, on any scale. A spectrum’s intensity is per unit wavelength, as a spectrometer records it.
phase (list[float] or numpy array or None) – [rad] the retrieved spectral or temporal phase at each sample, in the convention of FROG and SPIDER retrievals: the group delay is \(d\varphi/d\omega\), so a positive quadratic spectral phase is a positive group delay dispersion, and the instantaneous angular frequency is \(\omega_0 - d\varphi/dt\). Without a phase the pulse is taken as transform limited, with a warning. Default: None
fit (str) – the model fitted to the samples: ‘smooth’ (a smoothing spline of the intensity, with a polynomial phase of order 2 to 4 chosen by the fit, or a smoothing spline of the phase weighted by the intensity when no polynomial reaches
min_fit_quality, as for a pulse shaper’s output or a pulse broadened by self-phase modulation), ‘sech’ or ‘gaussian’ (the analytic shapes ofPulsedSource, fitted for width, center and chirp), default: ‘smooth’min_fit_quality (float) – the lowest fit quality accepted, in [0, 1], default: 0.99
background (float or 'auto' or None) – a constant background subtracted from
intensitybefore the fit, on the same scale asintensity(per unit wavelength for a spectrum), at least 0 and below the samples’ peak. ‘auto’ takes it as the mean of the outer 5 % of the samples at each end, and refuses the measurement when those ends slope or sit at different levels (by more than 1 % of the peak, or four times their noise), since they are then the pulse’s wings rather than a background. None subtracts nothing. Default: None
- class PulsedProcess
The nonlinear optics of one section for a pulsed simulation, for a section’s
nonlinear=.- Parameters:
chi2 (bool) – include \(\chi^{(2)}\), default: True
chi3 (bool) – include the Kerr effect, default: True
raman (bool) – include the delayed Raman part of the Kerr response, default: True
raman_mode (str) – ‘dominant’ (the response of the strongest field pattern, fast) or ‘full’, default: ‘dominant’
tpa (bool or None) – two-photon absorption on (True), off (False), or on wherever a material has a coefficient (None), default: None
multi_photon (bool or None) – three- and four-photon absorption, on (True) wherever a material has a three- or four-photon coefficient, or off (False or None). True raises an error for a cross-section in which no material has one. Default: None (off)
free_carriers (bool or None) – the electron-hole pairs that two-, three- and four-photon absorption make, with their absorption and index change: on (True), off (False), or on wherever an absorbing material has a free-carrier model (None). True raises an error for a cross-section in which no absorbing material has one. Default: None
carrier_lifetime (float or None) – [ns] the free-carrier lifetime, which depends on the waveguide, in place of the material’s own (1 ns for
Si). It must be positive. Default: None (the material’s lifetime)modes (list[int] or None) – the tracked mode indices at the center wavelength, default: None (the source’s mode or modes)
poling (Poling or None) – the section’s domain pattern, default: None (unpoled)
dispersion_samples (int or None) – wavelengths at which each cross-section is solved, Chebyshev nodes over the source’s
wavelength_range, at least 4, default: None (as many as the band’s width needs)pattern_threshold (float) – singular value, relative to the first, below which field patterns are dropped, in [0, 1), default: 1e-3
max_rank (int) – the largest number of field patterns.
PulseResponse.rank_reportsays where it binds and how much of each mode’s field that drops. Default: 12max_harmonic_modes (int) – on a \(\chi^{(2)}\) section, the most second-harmonic modes added to the tracked modes, ranked by their \(\chi^{(2)}\) overlap with the first tracked mode times the length they build over. 0 adds none. Default: 3
harmonic_coupling (float) – the weakest second-harmonic mode added, relative to the strongest, in [0, 1], default: 0.1
modal_search (str or tuple[float, float]) – where an unpoled \(\chi^{(2)}\) section’s modal phase matches are searched for: ‘broadened’ (where the launched pulse’s spectrum, or the pump’s spectrum anywhere in the section as it broadens, is within 30 dB of its peak), ‘launch’ (only where the launched pulse’s spectrum is within 30 dB of its peak), or a band
(min, max)of fundamental wavelengths [nm]. When a match lies outside the launched spectrum, ‘broadened’ first runs the pump alone (one mode, one field pattern, no second-harmonic modes) to find it. Default: ‘broadened’
Several \(\chi^{(2)}\) sections over one cross-section share its modes, which take the largest
max_harmonic_modesand the smallestharmonic_couplingamong them.
- class Poling
The domain pattern of a poled section. Give exactly one of
period,z_knotswithperiods,domain_walls, anddomain_lengths.- Parameters:
period (float) – [nm] a constant poling period
z_knots (list[float]) – [nm] positions along the section at which
periodsare given, interpolated between them (a chirp), at least 2periods (list[float]) – [nm] the local period at each knot
domain_walls (list[float]) – [nm] explicit domain wall positions along the section, strictly increasing
domain_lengths (list[float]) – [nm] the length of every domain in order, each > 0, the signs alternating from the first. The walls are the running sum: a wall at or past the end of the section is dropped, and when the domains end before the section does, the sign flips once more and the last domain runs to the end. This is the form
optimizevaries, every domain on its ownduty_cycle (float) – the fraction of each period in the first domain, default: 0.5
interpolation (str) – ‘linear’ or ‘spline’ between the knots, default: ‘linear’
inverted_first (bool) – start with an inverted domain, default: False
jitter_rms (float) – [nm] rms of a Gaussian random displacement of every wall, for fabrication tolerance studies, default: 0
seed (int) – the seed of the jitter, default: None
walls(section_length)returns the domain walls [nm] of any form over a section of that length, andto_domain_lengths(section_length)the length of every domain, which sum to the section length, so a design can start from a fixed or chirped poling.
- class PulseResponse
Returned by
get('pulse_response')afterEMEorpulse_propagate.spectrumis (records, modes, points), the root-energy spectrum of every tracked mode in \(\sqrt{\mathrm{J/Hz}}\) onfrequency[Hz], withwavelength[nm] the same axis,z[nm] the record positions andenergy[pJ] per record and mode.junction_lossis, per junction, the fraction of the arriving energy that left the tracked modes there, andrank_per_sliceandsamples_per_slicereport the field patterns and mode solves of each slice.window_gapis, per record, the longest stretch of the time window (as a fraction of it) that holds almost none of the energy of all the tracked modes together. The window is periodic, so below about 0.05 the pulse’s leading and trailing parts have met around it and wrapped onto each other, andnum_pointsshould grow (the solver warns). It does not depend on the comoving frame.edge_energyis, per record, the fraction of the energy in the outer 5 % of the time window around the comoving frame (the first tracked mode’s group delay), which says where the pulse sits relative to that frame, not whether it wraps.domain_walls[nm] the positions along the chain of the domain walls the run used (jitter included), andstepsandrejected_stepscount the propagation steps. For a measured source,measured_fitis the fit that was launched (seePulseMeasurement), and None otherwise.rank_reportgives, per slice, the field patterns used (rank), the numberpattern_thresholdasks for (natural_rank), themax_rankthat caps it and the share of each tracked mode’s field weight the patterns leave out (dropped_weight).absorbed_energyis the energy [pJ] each nonlinear absorption process took out of the tracked modes over the whole chain, a dictionary keyed'two_photon','three_photon','four_photon'and'free_carrier'for the processes that ran.band_energy(wavelength_min, wavelength_max, z=None, mode=None)returns the energy [pJ] in a band at the record nearestz(default: the output), summed over the tracked modes unlessmodeis given.band_power(...)returns the average power [W] of a pulse train, withrepetition_ratetaken from the source unless given.psd(z, mode)returns the spectral density in dB relative to 1 pJ/nm,envelope(z, mode)the time [fs] and complex envelope [\(\sqrt{\mathrm{W}}\)],smallest_window_gap()the smallestwindow_gapat any record (None for a response saved before it was reported),energy_outside_window()the largestedge_energy, andtotal_absorbed_energy()the sum ofabsorbed_energy[pJ], the energy every nonlinear absorption process took together.
- pulse_propagate
Propagate the pulse again through the chain the last
EMEprepared, without any mode solve (EMode3D only). Use it to try another poling, for example a chirp or fabrication jitter on the domain walls, at the cost of the propagation alone.- Parameters:
poling (Poling or dict or None) – a new domain pattern for every section with a
PulsedProcess(a singlePoling), or for the named sections (a dictionary of section name toPoling), default: None (keep the declared poling)records (int) – number of evenly spaced positions along the chain at which the spectrum is recorded, default: 100
local_error (float) – relative error allowed per propagation step, default: 1e-6
simulation_name (str) – simulation name, default: ‘emode’
The prepared chain lives for the session. After
open()of a saved file, runEMEagain first. The result is read back withget('pulse_response').