solprop.modes.stepindex#

Solve the exact, lossless vector eigenproblem of a circular step-index fibre.

The characteristic equation is evaluated after clearing its Bessel denominators; sign changes at Bessel poles are therefore never accepted as eigenvalues. TE means A + B = 0 and TM means A + (n_cl/n_co)**2 B = 0. The transverse profile is evaluated at an explicitly declared wavelength. See docs/guide/waveguides/step-index.md for the Snyder and Love references.

Module Attributes

PROFILE_MIN_W

Smallest cladding decay the frozen transverse profile is evaluated at.

Classes

StepIndexMode(radius, *[, core, cladding, ...])

Describe an exact vector mode with an explicitly frozen profile wavelength.

solprop.modes.stepindex.PROFILE_MIN_W = 0.1#

Smallest cladding decay the frozen transverse profile is evaluated at.

The outer radius is a max(2, 1 + log(1e8)/w), so w = 0.1 puts it at about 185 core radii and anything smaller integrates a nearly unguided field over a disc no fixed rule resolves. It bounds the frozen profile only: StepIndexMode.neff() has no floor and reports whatever the eigenvalue is.

class solprop.modes.stepindex.StepIndexMode(radius, *, core=None, cladding=None, kind='HE', n=1, m=1, parity='even', profile_wavelength, loss=0.0)[source]#

Bases: Displayed

Describe an exact vector mode with an explicitly frozen profile wavelength.

Solve the lossless Snyder and Love eigenproblem using the real parts of the material indices. Material absorption is not inferred; loss supplies the power attenuation independently. An optmat index (OptmatGlass) is held as its transparent approximation (lossless_index()): the real part, with the dropped k recorded for a run’s manifest and a MaterialRangeWarning once per run where the dropped absorption exceeds its bound (SEP 3, Q3). TE obeys A+B=0 and TM obeys A+(n_cl/n_co)**2*B=0, where A=J_0'/(u J_0) and B=K_0'/(w K_0). The public frequency methods require positive frequencies.

Attributes:
radiusfloat or ZProfile

Core radius in m, positive throughout the declared path.

coreGlassIndex or float or None

Core refractive index; None selects fused silica. An optmat index given here is held as its transparent counterpart.

claddingGlassIndex or float or None

Cladding refractive index; None selects the constant index 1. An optmat index given here is held as its transparent counterpart.

kind{‘HE’, ‘EH’, ‘TE’, ‘TM’}

Vector mode family in Snyder and Love’s convention.

nint

Azimuthal order, at least 1 for hybrids and 0 for TE/TM.

mint

Radial order, at least 1, counted from highest effective index.

parity{‘even’, ‘odd’}

Hybrid orientation; TE/TM have no distinct parity partner.

profile_wavelengthfloat

Required wavelength in m for the transverse profile, inside both material validity ranges and above the selected mode’s cutoff in frequency.

lossfloat or callable

Non-negative power attenuation in 1/m, constant or alpha(omega). A callable may supply its analytic slope as a derivative attribute.

core_radiusZProfile

Resolved radius path in m.

References

A. W. Snyder and J. D. Love, Optical Waveguide Theory (1983), chapter 12, Table 12-3. The book’s equation and table numbering has not been independently checked; the characteristic equation, the vector boundary conditions and the exact cutoffs were checked against F. Le Kien et al., Phys. Rev. A 97, 013821 (2018), Appendix C.

Examples

>>> mode = StepIndexMode(1.25e-6, profile_wavelength=835e-9)
>>> mode.z_constant, mode.scale_invariant
(True, False)
aeff(z=0.0)[source]#

Return the effective area of the frozen transverse profile.

Parameters:
zfloat, optional

Position along the fibre in m.

Returns:
float

Squared intensity integral divided by the quartic integral, in m².

at_parameters(values)[source]#

Freeze the supplied geometry parameter.

Parameters:
valuescollections.abc.Mapping

Any subset of core_radius, in m and strictly positive.

Returns:
StepIndexMode

Mode with the named radius frozen and its profile recomputed.

Raises:
ModeError

If a name is unknown or the radius is invalid.

property azimuthal_order: int[source]#

Return the azimuthal mode index n.

Returns:
int

The mode index n, dimensionless.

property channel_label: ChannelLabel[source]#

Return the exact vector family, its indices and its parity.

Returns:
ChannelLabel

Family, azimuthal and radial order, and the hybrid parity. An axially symmetric TE0m or TM0m channel has no parity partner, so its parity is None rather than the orientation its constructor defaulted to.

Examples

>>> from solprop.modes import StepIndexMode
>>> mode = StepIndexMode(1.25e-6, profile_wavelength=835e-9)
>>> mode.channel_label.display_label
'HE1,1:even'
cladding: GlassIndex | float | None = None#
core: GlassIndex | float | None = None#
core_radius: ZProfile#
cutoff_parameter()[source]#

Return the exact cutoff V for the profile wavelength’s material indices.

For dispersive materials the cutoff curve changes with frequency. This diagnostic uses the declared profile wavelength; the solver determines guidance using the material indices at each requested frequency.

Returns:
float

Dimensionless cutoff V. HE11 has cutoff zero. Hybrid orders n>=2 use the exact contrast-dependent equation, not its weak-guidance limit.

References

F. Le Kien et al., Phys. Rev. A 97, 013821 (2018), Appendix C, doi:10.1103/PhysRevA.97.013821.

dimlimits(z=0.0)[source]#

Return a polar disc enclosing the cladding tail to the declared decay.

Parameters:
zfloat, optional

Position along the fibre in m.

Returns:
tuple

Polar limits in m and rad, with R_out=max(2a,a*(1+log(1e8)/w)).

dneff_domega(omega, z=0.0)[source]#

Differentiate the exact eigenvalue equation analytically.

Only an absolute-loss callable without a derivative attribute is differenced.

Parameters:
omegaarray_like or float

Positive finite angular frequencies in rad/s, shape (n_omega,).

zfloat, optional

Position along the fibre in m.

Returns:
numpy.ndarray

Complex index derivative in s/rad, shape (n_omega,).

Raises:
ModeError

If the eigenpair or its derivative cannot be resolved.

electromagnetic_field(xy, omega, z=0.0)[source]#

Return unit-power E/H in the internal FFT convention.

Parameters:
xyarray_like

Cartesian (x, y) positions in m, shape (n_points, 2). Named apart from the polar points of field(), which this method does not share: these are Cartesian pairs. Interface points take the core value; the axis is evaluated by its analytic limit.

omegafloat

Positive angular frequency in rad/s in the bound guided band.

zfloat, optional

Position in m within the radius path.

Returns:
tuple of numpy.ndarray

Complex Cartesian E and H, each shape (n_points, 3), including longitudinal components. Units are V/m and A/m per sqrt(W); the full-domain Poynting flux is one, independently of the supplied points.

Raises:
ModeError

If the positions or frequency are invalid, the mode is too near cutoff, or attenuation/leaky fields are requested without a qualified adjoint.

Notes

This separate vector API leaves the frozen transverse field unchanged. Maxwell curl equations use exp(i omega t - i beta z). The radial roots, family counting and analytic dispersion derivative are unchanged.

field(points, z=0.0)[source]#

Return unnormalised Cartesian fields with the core value at r=a.

Parameters:
pointsnumpy.ndarray

Polar (r, theta) points in m and rad, shape (n_points, 2), r>=0.

zfloat, optional

Position along the fibre in m.

Returns:
numpy.ndarray

Real Cartesian components (E_x, E_y), shape (n_points, 2).

Raises:
ModeError

If points are non-finite, malformed or have negative radii.

classmethod from_numerical_aperture(radius, numerical_aperture, *, cladding=None, kind='HE', n=1, m=1, parity='even', profile_wavelength, loss=0.0)[source]#

Construct a fibre with the core index n_co = n_cl + NA^2/(2 n_cl).

Parameters:
radiusfloat or ZProfile

Positive core radius in m.

numerical_aperturefloat

Positive finite numerical aperture, dimensionless.

claddingGlassIndex or float or None, optional

Cladding index; None selects fused silica.

kind{‘HE’, ‘EH’, ‘TE’, ‘TM’}, optional

Vector mode family.

n, mint, optional

Azimuthal and radial indices, as in the class attributes.

parity{‘even’, ‘odd’}, optional

Hybrid orientation.

profile_wavelengthfloat

Required profile wavelength in m.

lossfloat or callable, optional

Power attenuation in 1/m.

Returns:
StepIndexMode

Fibre with an analytic material slope for its derived core index.

Raises:
ModeError

If the aperture or mode arguments are invalid.

kind: Literal['HE', 'EH', 'TE', 'TM'] = 'HE'#
loss: float | Callable[[Float[ndarray, 'n_omega']], Float[ndarray, 'n_omega']] = 0.0#
m: int = 1#
n: int = 1#
neff(omega, z=0.0)[source]#

Return the effective index, with positive imaginary part for loss.

Parameters:
omegaarray_like or float

Positive finite angular frequencies in rad/s, shape (n_omega,).

zfloat, optional

Position along the fibre in m.

Returns:
numpy.ndarray

Complex dimensionless index, shape (n_omega,).

Raises:
ModeError

If inputs are invalid or any frequency is below cutoff.

neff_minus_one(omega, z=0.0)[source]#

Return neff minus one by subtraction, appropriate for a solid core.

Unlike a dilute gas, a solid core’s refractivity is ordinarily of order unity and does not require the capillary’s cancellation-free expression.

Parameters:
omegaarray_like or float

Positive finite angular frequencies in rad/s, shape (n_omega,).

zfloat, optional

Position along the fibre in m.

Returns:
numpy.ndarray

Complex refractivity, shape (n_omega,).

normalisation(z=0.0)[source]#

Return the power normalisation of the transverse electric profile.

Parameters:
zfloat, optional

Position along the fibre in m.

Returns:
float

(epsilon0*c/2) times the transverse squared-field integral.

property orthogonal_polarisation: StepIndexMode | None[source]#

Return the other hybrid parity, or None for TE and TM.

Returns:
StepIndexMode or None

Opposite hybrid parity; None for TE and TM.

property parameter_paths: Mapping[str, ZProfile][source]#

Return the core-radius path carrying the entire z dependence.

Returns:
collections.abc.Mapping

The core_radius path in m.

parity: Literal['even', 'odd'] = 'even'#
principal_component(z=0.0)[source]#

Declare that the exact vector profile needs both Cartesian components.

Parameters:
zfloat, optional

Position along the fibre in m; orientation is independent of it.

Returns:
None

Both transverse components are resolved.

profile_wavelength: float#
radial_breaks(z=0.0)[source]#

Return the core boundary where the radial electric field jumps.

Parameters:
zfloat, optional

Position along the fibre in m.

Returns:
tuple of float

One radius in m.

radius: float | ZProfile#
property radius_is_constant: bool[source]#

Return whether the transverse geometry is constant along z.

Returns:
bool

True if the geometry is fixed along z.

property scale_invariant: bool[source]#

Return False because changing the radius changes the normalised frequency.

Returns:
bool

False, since V changes with core radius.

property z_constant: bool[source]#

Return whether the radius path is constant.

Returns:
bool

True if the radius path is constant.