solprop.modes.protocol#
The mode protocol: what the rest of solprop needs from a waveguide mode.
A mode is anything with an effective index and a transverse field profile. The linear
operator needs neff and its analytic frequency derivative (the co-moving frame,
ADR-006); the multimode transform needs the field at quadrature nodes and the geometry
of the cross-section; the mode-averaged normalisation needs the effective area; the
translation layer needs the three traits that say how the mode changes along z, and, for
a mode whose whole z dependence is a handful of scalar paths, the two members of
ParameterisedMode that let the operator be evaluated at parameter values
rather than at positions. Nothing here computes anything: implementations live in
solprop.modes and, for a dispersion-specified GNLSE mode, in
solprop.nonlinear.gnlse.
Conventions (docs/dev/conventions.md section 5): Im n_eff > 0 is loss;
n_eff - 1 is available without cancellation for gases through
Mode.neff_minus_one(); points are (r, theta) for a polar cross-section and
(x, y) for a Cartesian or slab one, in metres and radians; fields are the transverse
Cartesian components (E_x, E_y) of the unnormalised profile, whose normalisation
N and effective area follow from them.
A mode uniform in y – the hollow planar guide of solprop.modes.slab –
declares the "slab" cross-section and the optional transverse_measure trait
"per_unit_width": its normalisation is a power per metre of y, its effective
“area” is an effective width in metres, and the powers and energies of a run on it are
per unit width (TransverseMeasure). A mode without the trait is "area".
Module Attributes
The attribute names under which a mode declares its cross-section along z. |
|
How a mode parametrises its cross-section: |
|
What the transverse integral of a mode or a grid measures. |
|
Name one transverse Cartesian field component. |
|
Which of a degenerate azimuthal pair a channel is; |
|
Which circular partner a complex degenerate channel is. |
Classes
|
Name one physical channel of a waveguide, independently of its position. |
|
A guided mode as consumed by the linear operator, the transforms and the stats. |
|
A mode whose whole z dependence runs through named scalar paths. |
- class solprop.modes.protocol.ChannelLabel(family, azimuthal_order, radial_order, parity, handedness, display_label)[source]#
Bases:
DisplayedName one physical channel of a waveguide, independently of its position.
The identity the mode axis carries: the family and the quantum numbers a person quotes, with
Nonewherever a family has no such number – an axially symmetricTE_0mhas no parity partner, so its parity isNone, and a real basis has no handedness. The label belongs to the mode, not to its index in a collection: a set’s order is the order of its tuple, and two members may carry the same label only where they are genuinely the same physical channel in different gauges.Parity is defined once, here, for every family.
"even"is the member whose transverse pattern is thecos((n - 1) theta)one about the x axis – forn = 1that is the x-polarised member – and"odd"is its quarter-turn partner,sin((n - 1) theta)about x. A family reports the parity of the physical pattern, whatever its own construction is written in: an exact step-indexHE_nmbuilds the pair fromcos(n theta)andsin(n theta)on the radial component and a MarcatiliHE_nmfrom a rotation angle, and both land on this one definition. Note thatazimuthal_orderis the family indexnwhile the parity names the(n - 1)-fold pattern the transverse vector field actually has; the two differ by one, and that is the physics of a hybrid mode rather than a slip.- Attributes:
- familystr
Non-empty family name:
HE,EH,TE,TM,LP,rector a provider’s own declared family.- azimuthal_orderint or None
Non-negative azimuthal index
n, orNonewhere the family has none.- radial_orderint or None
Positive radial index
m, orNonewhere the family has none.- parity{‘even’, ‘odd’} or None
Which of a degenerate azimuthal pair, by the definition above, or
Nonefor a channel with no parity partner or in an unlabelled gauge.- handedness{‘left’, ‘right’} or None
Which circular partner of a complex degenerate pair, or
Nonefor a real basis. The convention is defined once, bysolprop.modes.guide.circular_pair():leftis(e_even - i e_odd)/sqrt(2), positive helicity in the internal convention and positive StokesVin the optics one (docs/guide/setup/polarisation.md).- display_labelstr
Non-empty stable text for a person, a legend or a file:
HE1,1:even.
Examples
>>> from solprop.modes.protocol import ChannelLabel >>> label = ChannelLabel("TE", 0, 1, None, None, "TE0,1") >>> label.display_label, label.parity ('TE0,1', None)
- as_mapping()[source]#
Return the label as the serialisable mapping an identity carries.
- Returns:
- collections.abc.Mapping
The six fields by name, in the order they are declared, with
Nonewhere a family has no such quantum number. This is what a provider’sidentitypublishes and what output schema 7 will persist.
Examples
>>> from solprop.modes.protocol import ChannelLabel >>> mapping = ChannelLabel("TE", 0, 1, None, None, "TE0,1").as_mapping() >>> mapping["display_label"], mapping["parity"] ('TE0,1', None)
- classmethod from_mapping(mapping)[source]#
Rebuild a label from the mapping
as_mapping()produced.The round trip a provider’s
identity["channels"]and output schema 7 need: the mapping has been through JSON, so every value arrives as an ordinary Python object and is checked here before it becomes a label.- Parameters:
- mappingcollections.abc.Mapping
Exactly the six keys of
as_mapping(), with a string family and display label, integer orNoneorders, and string orNoneparity and handedness.
- Returns:
- ChannelLabel
The label.
- Raises:
- solprop.exceptions.ModeError
If a key is missing or extra, or a value has the wrong type.
Examples
>>> from solprop.modes.protocol import ChannelLabel >>> label = ChannelLabel("TE", 0, 1, None, None, "TE0,1") >>> ChannelLabel.from_mapping(label.as_mapping()) == label True
- solprop.modes.protocol.CrossSection#
How a mode parametrises its cross-section:
(r, theta),(x, y)orxalone.A
"slab"cross-section is uniform in y: its limits are one-tuples(-a,)and(a,)in x, and its points are still(x, y)pairs, withy = 0on the rule’s nodes and the profile independent of it.alias of
Literal[‘polar’, ‘cartesian’, ‘slab’]
- solprop.modes.protocol.GEOMETRY_PATH_NAMES = ('core_radius', 'width_x', 'width_y', 'area_path')#
The attribute names under which a mode declares its cross-section along z.
A hollow capillary declares
core_radius, a rectangular guide its two widths, and asolprop.nonlinear.gnlse.SpecifiedModeitsarea_path: the effective area is the whole of its cross-section, so its breakpoints are cross-section kinks exactly as a bore corner is. Each is asolprop.profiles.ZProfile.The names live here because two modules must agree on them and neither may import the other:
solprop.translate.modalwalks them for the kinks the tables and the schedule land on, andsolprop.nonlinear.gnlsewalks them for the z ownership of a mode a specified fibre is built from. The translation layer’s tuple is these names plusdispersion_path.
- solprop.modes.protocol.Handedness#
Which circular partner a complex degenerate channel is.
alias of
Literal[‘left’, ‘right’]
- class solprop.modes.protocol.Mode(*args, **kwargs)[source]#
Bases:
ProtocolA guided mode as consumed by the linear operator, the transforms and the stats.
Every method takes the position
zin metres, so that tapers and pressure gradients are ordinary cases; a z-independent mode ignores it and reportsz_constant.- aeff(z=0.0)[source]#
Return the effective area.
- Parameters:
- zfloat, optional
Position along the waveguide, m.
- Returns:
- float
A_eff = (∫|e|² dA)² / ∫|e|⁴ dAin m²; for a mode uniform in y (transverse_measure = "per_unit_width") the same ratio over x alone, an effective width in m.
- property azimuthal_order: int[source]#
Highest azimuthal order
hof the profile, which sets the theta rule size.The periodic trapezoid rule is exact for trigonometric polynomials of degree at most
n_theta - 1and cubic products of order-hmodes reach degree4 h, so the transform needsn_theta > 4 h.
- property channel_label: ChannelLabel[source]#
Name the physical channel this mode is, with its quantum numbers.
The label is a property of the mode itself, not of its place in a set:
solprop.modes.collection.ModeCollection.channel_labelsis the ordered tuple of its members’ labels, and output schema 7 persists them beside the mode axis.
- dimlimits(z=0.0)[source]#
Return the cross-section parametrisation and the integration limits.
- Parameters:
- zfloat, optional
Position along the waveguide, m.
- Returns:
- tuple
(kind, lower, upper):"polar"with(r, theta)limits,"cartesian"with(x, y)limits, or"slab"with the one-tuplexlimits of a guide uniform in y, in m and rad.
- dneff_domega(omega, z=0.0)[source]#
Return the analytic frequency derivative of the effective index.
- Parameters:
- omeganumpy.ndarray
Angular frequencies, rad/s, shape
(n_omega,), strictly positive: no waveguide has a mode at zero frequency, and the linear operator evaluates on the active band, which excludes it.- zfloat, optional
Position along the waveguide, m.
- Returns:
- numpy.ndarray
d n_eff / d omegain s/rad, complex, shape(n_omega,). Analytic where the model allows (ADR-006); an implementation that differences must say so in its docstring and report the accuracy it reaches.
- field(points, z=0.0)[source]#
Return the transverse field components at points of the cross-section.
- Parameters:
- pointsnumpy.ndarray
Shape
(n_points, 2):(r, theta)or(x, y)perdimlimits(); a slab mode readsxand ignoresy.- zfloat, optional
Position along the waveguide, m.
- Returns:
- numpy.ndarray
(E_x, E_y)of the unnormalised profile at each point, shape(n_points, 2), real.
- neff(omega, z=0.0)[source]#
Return the complex effective index.
- Parameters:
- omeganumpy.ndarray
Angular frequencies, rad/s, shape
(n_omega,), strictly positive: no waveguide has a mode at zero frequency, and the linear operator evaluates on the active band, which excludes it.- zfloat, optional
Position along the waveguide, m.
- Returns:
- numpy.ndarray
n_eff(omega, z), complex, shape(n_omega,);Im n_eff > 0is loss.
- neff_minus_one(omega, z=0.0)[source]#
Return
n_eff - 1formed without cancellation.- Parameters:
- omeganumpy.ndarray
Angular frequencies, rad/s, shape
(n_omega,), strictly positive: no waveguide has a mode at zero frequency, and the linear operator evaluates on the active band, which excludes it.- zfloat, optional
Position along the waveguide, m.
- Returns:
- numpy.ndarray
n_eff - 1, complex, shape(n_omega,), exact to rounding for a gas-filled waveguide (docs/dev/conventions.mdsection 5).
- principal_component(z=0.0)[source]#
Return the sole nonzero Cartesian component, or both components as None.
This is a property of the continuous profile, not a test at quadrature nodes: an aliased rule must not hide a component that the mode actually carries.
- Parameters:
- zfloat, optional
Position along the waveguide, m.
- Returns:
- {‘x’, ‘y’} or None
The sole nonzero component;
Nonemeans both components are needed.
- class solprop.modes.protocol.ParameterisedMode(*args, **kwargs)[source]#
-
A mode whose whole z dependence runs through named scalar paths.
A Marcatili mode reaches
zonly through its core radiusa(z)and its number densityrho(z), so its effective index is a function of those two scalars and the frequency:n_eff(omega, z) = n_eff(omega; a(z), rho(z)). Stating that here is what letssolprop.linear.dispersion_operator()be called on parameter values rather than on positions, and so lets the translation layer expand the cumulative operator in the parameters instead of tabulating it along z (docs/dev/kernel-contract.mdsection 3).A declared path is a statement of z ownership – this is where the mode’s z dependence lives, so these are its kinks and this is what an expansion may be taken in – and not a statement that the linear operator depends on it: a specified mode declares its effective area, whose whole effect is on the nonlinear coefficient, and the operator is then expanded in a parameter it does not depend on, at degree zero.
A mode whose declared paths are not the whole of its z dependence says so with the optional
parameters_own_ztrait, whichsolprop.translate.linop.parameters_own_z()reads by name. It defaults toTrue– what every mode written before the trait existed implied – and a mode that reportsFalsekeeps the translation layer on the z table instead of an expansion its parameters cannot reproduce. The case is asolprop.nonlinear.gnlse.SpecifiedModewhose dispersion follows a path beside its declared area: the area is still its kinks, but freezing the area would leave the dispersion moving.A mode that does not implement this is not less capable, only less exploitable: the translation layer falls back to the z table for it, which is the general representation. A z-constant mode need not implement it either, having a cheaper path still.
- at_parameters(values)[source]#
Return the same mode with the named paths frozen at the given values.
- Parameters:
- valuescollections.abc.Mapping
Path name to value, in the units of
parameter_paths. Every name must be one of that mapping’s keys; a name it does not know is an error rather than a silent no-op. Names left out keep their path.
- Returns:
- Mode
A mode that reports
z_constantand reproduces this one at every position where its paths take the given values.
- Raises:
- solprop.exceptions.ModeError
If a name is not a declared path, or a value is outside the path’s range of validity.
- property parameter_paths: Mapping[str, ZProfile][source]#
Return the named scalar paths the effective index depends on.
- Returns:
- collections.abc.Mapping
Path name to
ZProfile, for example{"core_radius": ..., "density": ...}. Every key is accepted byat_parameters(); constant paths are included, so that a caller sees the whole dependence and decides for itself which of them vary.
- solprop.modes.protocol.Parity#
Which of a degenerate azimuthal pair a channel is;
ChannelLabeldefines it.Not restated here: one definition, in one place.
alias of
Literal[‘even’, ‘odd’]
- solprop.modes.protocol.PolarisationComponent#
Name one transverse Cartesian field component.
alias of
Literal[‘x’, ‘y’]
- solprop.modes.protocol.TransverseMeasure#
What the transverse integral of a mode or a grid measures.
"area"is an integral over the whole cross-section: powers in W, energies in J, effective areas in m²."per_unit_width"is an integral over x alone for a geometry uniform in y: powers in W/m, energies in J/m, the effective “area” an effective width in m. Intensities are W/m² either way. A mode declares it with an optionaltransverse_measureproperty, read by name, whose absence means"area".alias of
Literal[‘area’, ‘per_unit_width’]