Electric and magnetic mode fields#
Full vector modes supply electric and magnetic fields, with their phases and longitudinal components, rather than only a scalar transverse profile. These fields determine both physical power and nonlinear coupling in a general modal calculation. The solid-fibre workflow shows how to construct a guide before using this reference.
Full electric and magnetic mode fields#
This chapter serves the general modal route,
which propagates several solid-guide channels with their full vector fields and a
power-orthogonal metric. That route needs a mode’s complete vector field, not only its
transverse profile. StepIndexMode.electromagnetic_field(xy, omega, z) returns complex Cartesian
(E_x, E_y, E_z) and (H_x, H_y, H_z) at explicit Cartesian positions in metres.
Both fields are normalised to unit full-domain Poynting power, independently of those
points, in V/m and A/m per sqrt(W). These fields use the internal FFT convention,
exp(i omega t - i beta z). They are separate from Mode.field, which is a real,
frozen-frequency, two-component transverse profile used by the mode-averaged and
multimode routes; both use the same exact bound roots and family and cutoff
counting.
In each homogeneous region, with q² = epsilon_r (omega/c)² - beta², eliminating
the transverse components from Maxwell’s curl equations gives
The core uses regular Bessel functions and the exterior uses decaying modified
Bessel functions. Analytic axis limits avoid division by zero. The implementation
uses exponentially scaled exterior functions. Both hybrid parities and TE/TM
sectors have all three components, including components which vanish by symmetry.
Attenuating/leaky fields are refused: a prescribed attenuation coefficient does
not establish a complex eigenfield, its reciprocal adjoint, or its exterior norm.
The cutoff guard of the transverse profile, PROFILE_MIN_W, applies here too.
Use a provider to obtain true-power-normalised fields:
import numpy as np
from solprop.constants import C
from solprop.modes import IndexMaterial, ModalGuide, StepIndexMode
omega = 2 * np.pi * C / 835e-9
mode = StepIndexMode(250e-9, core=1.45, cladding=1.0, profile_wavelength=835e-9)
guide = ModalGuide.from_step_index(
[mode], core=IndexMaterial(1.45), cladding=IndexMaterial(1.0)
)
provider = guide.field_provider
nodes = provider.node_rule(omega)
sample = guide.solve(omega, 0.0, nodes=nodes)
A material law is a PermittivityLaw: anything with permittivity(omega), an
omega_domain and an identity, of which IndexMaterial is the adapter for a
glass law or a constant index. It is named for the law, not for a material,
because solprop.optics.Material in the flat solprop.sol namespace is a length
of a real medium and the two must not be confused. A MaterialRegion gives one
law an annular region, whose radii may follow declared paths.
ModalNodeRule owns Cartesian positions, positive area weights and an integer
material-region index at every node. Its panel machinery is that of the
transverse quadrature. The step-index builder splits at the core
interface and integrates the omitted cladding power separately. Increasing radial
and angular resolution tests quadrature error independently of the tail.
Every provider builds its rule through one signature,
node_rule(omega, z=0.0, *, n_r=..., n_theta=None). The frequency is required
even where the mesh does not depend on it, because the power a rule discards
beyond its outer radius does: both providers put that exactly integrated fraction
in the rule’s identity["tail_power_bound"]. n_theta=None asks the provider for
the angular count its channels’ azimuthal orders need, 4(n + 1) + 1, which is
exact for their quartic products; the radial provider uses at least nine.
ModalSample.electric and .magnetic have shape (n_nodes, 3, n_modes) and units
V/m and A/m per sqrt(W). Each physical parity partner is one channel. The
Hermitian Poynting product is
Every provider refuses an unsupported channel by name – too near cutoff, an
uncertifiable tail, a boundary residual above its bound – rather than masking
it, so ModalSample.valid is all True in any sample a provider returns. The
field is there so that a future provider which can honestly return a partial set
has somewhere to say so, and tracking refuses a sample whose mask is not all
True.
The fields are normalised over the full radial domain, separately from the
caller’s node rule. Their sampled flux matrix therefore exposes missing power in
a truncated or inaccurate rule. It is not forced to be the identity. Reciprocal
backward fields satisfy e_minus=e.conj(), h_minus=-h.conj() for this bound,
lossless model, giving C=-4W. The internal source functional is
-i omega/4 * W^-1 integral(e.conj() dot P_NL) dA. It includes the longitudinal
electric field and differs from an electric-only coefficient-recovery inverse.
The full-vector Kerr contraction is discussed by
Afshar and Monro. solprop derives it independently
from Maxwell’s equations, because the paper’s printed equations are not self-consistent
in places: the linear electric term of its Eq. (5) lacks a factor \(\omega\), the integral
in its Eq. (8) and the definition of \(N\) that follows differ by a factor two, and the
displayed sign of the nonlinear source in its Eq. (9) differs from direct substitution
of its curl equations. The sign used here is fixed by the positive-\(n_2\) plane-wave
limit.
Putting the instantaneous isotropic Kerr polarisation of an analytic signal,
P = eps0 chi3 (2 |E|^2 E + (E.E) E*) / 4, into that functional at unit
amplitude and unit flux leaves -i gamma with
which is solprop.nonlinear.normalisation.modal_kerr_coefficient(electric, weights, chi3, omega). The susceptibility is per node, so a linear cladding is
excluded by being zero there and no region ownership is assumed. Both the
longitudinal field and the |E.E|^2 term are in it, and neither is in the scalar
n2 omega / (c A_eff): on the 250 nm strand the vector coefficient is 25 %
larger (0.541771892 against 0.432424108 W⁻¹m⁻¹), while at weak guidance the two
agree to better than 0.2 %.
The displayed \(\gamma\) above is the unit-flux one, which is what a provider’s
normalisation declares over the whole physical domain. A channel whose sampled flux
\(W_{mm}\) is not one divides by it, and metric= is how that is said: a positive float
is read as this channel’s own \(W_{mm}\), while a square Hermitian
\((n_\text{modes}, n_\text{modes})\) array with channel= gives the
coefficient \([W^{-1}]_{mm}\) — which is what the general modal route’s own projection map
contracts, and which equals \(1/W_{mm}\) only while \(W\) is diagonal. On a sampled basis
the number a run executes is therefore the unit-flux \(\gamma\) times \([W^{-1}]_{mm}\), and
the difference between the two is the basis’s measured departure from orthonormal.