solprop.modes.collection#
Ordered, validated sets of modes, and the overlaps between them.
A multimode simulation propagates a set of modes through one transverse quadrature
rule and one pair of transform matrices, which only works if they share a
cross-section. ModeCollection is that set: ordered, because the mode axis of
the kernel state is, and validated once at construction rather than at every use.
It also answers the two questions the translation layer asks of a mode set – whether the azimuthal coordinate has to be resolved, and to what order – and offers the overlaps that say whether the set is orthonormal at all.
overlap() integrates adaptively with scipy.integrate.dblquad(),
deliberately not on the fixed rule. The fixed rule’s orthonormality is the thing
being checked in tests/modes/test_quadrature.py; if the check used the same rule it
would be true by construction and would say nothing.
Overlaps use the package normalisation (docs/dev/conventions.md section 4),
so a mode overlaps itself by one. For a slab set (solprop.modes.slab) the
integral is over x alone, per metre of y, with scipy.integrate.quad().
Functions
|
Return the matrix of normalised overlaps of a mode set. |
|
Return the normalised overlap integral of two modes. |
|
Expand a mode set so that each degenerate mode carries both polarisations. |
|
Return what a mode set's transverse integrals measure, refusing a mixture. |
Classes
|
An ordered set of modes sharing one cross-section. |
- class solprop.modes.collection.ModeCollection(modes)[source]#
Bases:
Displayed,Sequence[Mode]An ordered set of modes sharing one cross-section.
Validated once, at construction: the mode axis of the kernel state is positional, and one transform matrix serves the whole set, so a set whose members disagree about the geometry is not a set.
- Attributes:
- modessequence of Mode
The modes, in the order the mode axis will carry them. Any sequence is accepted and is stored as a tuple, so a collection cannot be changed after it has been validated.
- property azimuthal_order: int[source]#
Return the highest azimuthal order in the set.
- Returns:
- int
The bound that fixes how many azimuthal nodes a quartic product needs,
n_theta >= 4 h + 1.
- property channel_labels: tuple[ChannelLabel, ...][source]#
Return each member’s physical label, in the order of the mode axis.
- Returns:
- tuple of ChannelLabel
The members’ own
solprop.modes.protocol.Mode.channel_label, in order. A label a family does not have isNone, never a string standing for one: an axially symmetric TE0m or TM0m channel has no parity partner, so its parity isNone, exactly as its handedness is. Output schema 7 persists these labels.
Examples
>>> from solprop.modes import MarcatiliMode >>> from solprop.modes.collection import ModeCollection >>> modes = ModeCollection([MarcatiliMode(125e-6, "He", 1.0)]) >>> [label.display_label for label in modes.channel_labels] ['HE1,1:even']
- dimlimits(z=0.0)[source]#
Return the cross-section the whole set shares.
- Parameters:
- zfloat, optional
Position along the waveguide, m.
- Returns:
- Raises:
- ModeError
If the modes disagree at this position, which a taper of one mode but not another would cause.
Examples
>>> from solprop.modes import MarcatiliMode >>> from solprop.modes.collection import ModeCollection >>> ModeCollection([MarcatiliMode(125e-6, "He", 1.0)]).dimlimits()[0] 'polar'
- classmethod he1m(radius, gas, pressure, count, *, model='full', loss=True, cladding=None, temperature=293.15, susceptibility=None)[source]#
Build the first count HE_1m modes of one gas-filled capillary.
The linearly polarised hybrid modes of a hollow capillary, in the order of their radial index. They share a cross-section by construction, their azimuthal order is zero, so no azimuthal quadrature is needed, and they are the set a capillary run uses unless told otherwise.
Every keyword after count is
MarcatiliMode’s own and is given to each mode unchanged, so a set can carry a test-only cladding or gas susceptibility the way a single mode can.- Parameters:
- radiusfloat or ZProfile
Core radius, m, constant or along z.
- gasGas or str
Filling gas.
- pressurefloat or ZProfile
Fill pressure, bar, constant or along z.
- countint
How many modes, at least one; the modes are HE_11 to HE_1count.
- model{‘full’, ‘reduced’}, optional
Which Marcatili model the modes use.
- lossbool, float or callable, optional
Whether to include propagation loss, or the loss to use.
- claddingGlassIndex, complex or None, optional
The cladding index;
Noneis the package default silica.- temperaturefloat or ZProfile, optional
Gas temperature, K, or a path of it along z.
- susceptibilityGasSusceptibility or None, optional
A susceptibility to use in place of the built-in gas’s.
- Returns:
- ModeCollection
The validated set, in radial order.
- Raises:
- ModeError
If count is below one.
Examples
>>> from solprop.modes import ModeCollection >>> modes = ModeCollection.he1m(125e-6, "He", 0.8, 4) >>> len(modes), modes[3].m, modes.azimuthal_order (4, 4, 0)
- classmethod marcatili(radius, gas, pressure, kinds, n, m, *, model='full', loss=True, cladding=None, temperature=293.15, susceptibility=None)[source]#
Build an ordered mixture of hybrid and transverse capillary modes.
- Parameters:
- radiusfloat or ZProfile
Core radius, m, constant or along z.
- gasGas or str
Filling gas.
- pressurefloat or ZProfile
Fill pressure, bar, constant or along z.
- kindssequence of {‘HE’, ‘TE’, ‘TM’}
Family of each mode, non-empty.
- nsequence of int
Azimuthal indices, one per family; nonzero for HE and zero for TE/TM.
- msequence of int
Positive radial indices, one per family.
- model{‘full’, ‘reduced’}, optional
Marcatili approximation used by every mode.
- lossbool, float or callable, optional
Propagation-loss specification passed to every mode.
- claddingGlassIndex, complex or None, optional
Cladding index;
Noneselects the package default silica.- temperaturefloat or ZProfile, optional
Gas temperature, K, positive, or a path of it along z.
- susceptibilityGasSusceptibility or None, optional
Explicit susceptibility in place of the selected fit.
- Returns:
- ModeCollection
Modes in the input order, all with
phi = 0. Usewith_polarisations()to add degenerate partners.
- Raises:
- ModeError
If the index sequences are empty, have different lengths, or describe an invalid mode.
Examples
>>> from solprop.modes import ModeCollection >>> modes = ModeCollection.marcatili( ... 125e-6, "He", 1.0, ["HE", "HE", "TM"], [1, 2, 0], [1, 1, 1] ... ) >>> len(modes), modes.azimuthal_order (3, 1)
- property needs_full_rule: bool[source]#
Return whether the azimuthal coordinate has to be resolved.
- Returns:
- bool
Falsefor a set whose products are azimuthally symmetric – any set ofHE_1mmodes – which then needs the radial rule alone, and for a slab set, which is uniform in y;Trueotherwise.
- orthonormality(z=0.0)[source]#
Return the matrix of normalised overlaps of the set.
- Parameters:
- zfloat, optional
Position along the waveguide, m.
- Returns:
- numpy.ndarray
Shape
(n_modes, n_modes); the identity for an orthonormal set.
Examples
>>> import numpy as np >>> from solprop.modes import MarcatiliMode >>> from solprop.modes.collection import ModeCollection >>> modes = ModeCollection( ... [MarcatiliMode(125e-6, "He", 1.0, m=m) for m in (1, 2)] ... ) >>> bool(np.max(np.abs(modes.orthonormality() - np.eye(2))) < 1e-9) True
- property scale_invariant: bool[source]#
Return whether every mode rescales with the core radius.
- Returns:
- bool
Truewhen the transform may rescale its matrices along a taper rather than rebuilding them.
- classmethod slab(half_gap, orders, gas=None, pressure=0.0, *, polarisation='te', loss=True, cladding=None, temperature=293.15, susceptibility=None, mixture=None)[source]#
Build the given orders of one hollow planar guide, uniform in y.
A centred, symmetric launch couples only to odd orders, so the set a compressor run wants is usually
(1, 3, 5); an offset or tilted launch needs the even ones too. Every keyword isSlabMode’s own and is given to each mode unchanged. For TE and TM rows in one set, build the two polarisations and pass them to the constructor, or usewith_polarisations(): each is a distinct mode with its own row.- Parameters:
- half_gapfloat or ZProfile
Half the plate separation in m, constant or along z.
- orderssequence of int
Mode orders
p >= 1, non-empty and without repeats, in state order.- gasGas, str or None, optional
Filling gas; None for vacuum or an explicit mixture.
- pressurefloat or ZProfile, optional
Gas pressure in bar, constant or along z; default zero.
- polarisation{‘te’, ‘tm’}, optional
"te"(E along y, the default) or"tm"(E along x), for every order.- lossbool, float or callable, optional
Inherited mode loss policy.
- claddingGlassIndex, complex or None, optional
Plate index; None selects the default silica.
- temperaturefloat, optional
Gas temperature in K.
- susceptibilityGasSusceptibility or None, optional
Explicit gas susceptibility.
- mixtureMixture or None, optional
Ordered species and density paths; owns the gas and susceptibility.
- Returns:
- ModeCollection
The validated set, in the order given.
- Raises:
- ModeError
If orders is empty, repeats an order, or describes an invalid mode.
Examples
>>> from solprop.modes import ModeCollection >>> modes = ModeCollection.slab(63.5e-6, (1, 3, 5), "Ar", 1.0) >>> [label.display_label for label in modes.channel_labels] ['TE1', 'TE3', 'TE5'] >>> modes.transverse_measure, modes.needs_full_rule ('per_unit_width', False)
- property transverse_measure: Literal['area', 'per_unit_width'][source]#
Return what the set’s transverse integrals measure.
- Returns:
- str
"per_unit_width"for a slab set, whose powers are W/m and energies J/m, and"area"otherwise (transverse_measure()).
- classmethod vincetti(radius, gas=None, pressure=0.0, count=1, *, lattice, loss=True, cladding=None, temperature=293.15, susceptibility=None, mixture=None)[source]#
Build the first count HE_1m modes of a tube-lattice fibre.
The field and transverse quadrature remain Marcatili’s. Corrections and loss are fundamental-mode fits; higher radial orders log that limitation.
- Parameters:
- radiusfloat or ZProfile
Positive core radius in m, constant or along z.
- gasGas, str or None, optional
Filling gas; None for vacuum or an explicit mixture.
- pressurefloat or ZProfile, optional
Gas pressure in bar, constant or along z; default zero.
- countint, optional
Number of modes, at least one, in radial order.
- latticeTubeLattice
Tube geometry shared by all modes.
- lossbool, float or callable, optional
Inherited mode loss policy.
- claddingGlassIndex, complex or None, optional
Tube index; None selects the default silica.
- temperaturefloat or ZProfile, optional
Gas temperature in K, or a path of it along z.
- susceptibilityGasSusceptibility or None, optional
Explicit gas susceptibility.
- mixtureMixture or None, optional
Ordered species and density paths; owns the gas and susceptibility.
- Returns:
- ModeCollection
Validated modes sharing the tube geometry and cross-section.
- Raises:
- ModeError
If the mode count or geometry is invalid.
- classmethod with_polarisations(modes)[source]#
Build a collection carrying both polarisations of every degenerate mode.
- Parameters:
- modessequence of Mode
The spatial modes.
- Returns:
- ModeCollection
The expanded set, in the fixed order of
polarisation_pairs().
Examples
>>> from solprop.modes import MarcatiliMode >>> from solprop.modes.collection import ModeCollection >>> modes = [MarcatiliMode(125e-6, "He", 1.0, m=m) for m in (1, 2)] >>> len(ModeCollection.with_polarisations(modes)) 4
- solprop.modes.collection.orthonormality(modes, z=0.0)[source]#
Return the matrix of normalised overlaps of a mode set.
- Parameters:
- modessequence of Mode
The modes, non-empty.
- zfloat, optional
Position along the waveguide, m.
- Returns:
- numpy.ndarray
Shape
(n_modes, n_modes), symmetric, the identity for an orthonormal set.
- Raises:
- ModeError
If modes is empty, or the modes do not share a cross-section.
Examples
>>> import numpy as np >>> from solprop.modes import MarcatiliMode >>> from solprop.modes.collection import orthonormality >>> modes = [MarcatiliMode(125e-6, "He", 1.0, m=m) for m in (1, 2)] >>> bool(np.max(np.abs(orthonormality(modes) - np.eye(2))) < 1e-9) True
- solprop.modes.collection.overlap(first, second, z=0.0)[source]#
Return the normalised overlap integral of two modes.
- Parameters:
- first, secondMode
The modes, which must share a cross-section.
- zfloat, optional
Position along the waveguide, m.
- Returns:
- float
1for a mode with itself and0for an orthogonal pair. Integrated adaptively, not on the transform’s fixed rule, so that the rule can be checked against it.
- Raises:
- ModeError
If the modes do not share a cross-section, or either has no closed-form normalisation.
Examples
>>> from solprop.modes import MarcatiliMode >>> from solprop.modes.collection import overlap >>> mode = MarcatiliMode(125e-6, "He", 1.0) >>> f"{overlap(mode, mode):.9f}" '1.000000000'
- solprop.modes.collection.polarisation_pairs(modes)[source]#
Expand a mode set so that each degenerate mode carries both polarisations.
A vector run propagates the two orthogonal polarisation states of a hybrid mode as two entries on the mode axis. The order is fixed and is the obvious one – each mode immediately followed by its partner – because the mode axis of the kernel state is positional and a reordering would be silent.
A mode with no degenerate partner, such as
TE_0morTM_0m, is carried once.- Parameters:
- modessequence of Mode
The spatial modes.
- Returns:
- tuple of Mode
The expanded set.
- Raises:
- ModeError
If a mode cannot say whether it has a partner, which every ported mode can.
Examples
>>> from solprop.modes import MarcatiliMode >>> from solprop.modes.collection import polarisation_pairs >>> pairs = polarisation_pairs([MarcatiliMode(125e-6, "He", 1.0)]) >>> len(pairs), f"{pairs[1].phi:.4f}" (2, '1.5708')
- solprop.modes.collection.transverse_measure(modes)[source]#
Return what a mode set’s transverse integrals measure, refusing a mixture.
- Parameters:
- modessequence of Mode
The modes, non-empty. Each reports the optional
transverse_measuretrait by name; a mode without it takes the measure of the mode it was built from – asolprop.nonlinear.gnlse.SpecifiedModemade from a slab mode keeps its source’s per-unit-width normalisation and area – and measures an area when there is none.
- Returns:
- str
"area"or"per_unit_width"(solprop.modes.protocol.TransverseMeasure).
- Raises:
- ModeError
If the set is empty, or mixes a per-unit-width mode with an area mode, whose powers would be in W/m and W in one state.
Examples
>>> from solprop.modes import MarcatiliMode, SlabMode, transverse_measure >>> transverse_measure([MarcatiliMode(125e-6)]) 'area' >>> transverse_measure([SlabMode(50e-6)]) 'per_unit_width'