solprop.modes.material#

Describe material laws and region ownership independently of longitudinal paths.

Module Attributes

JsonValue

Anything solprop.output.schema.serialise() may return, and therefore anything JSON can carry.

MEASURED_DIGITS

Significant digits a measured float keeps when it enters an identity.

MaterialResponse

What a material region may declare: the instantaneous cubic, the delayed tensor.

Functions

quantised_measurement(value)

Return a measured float rounded to MEASURED_DIGITS significant digits.

Classes

GasKerr(fill)

Declare a region's gas fill as the source of its electronic cubic response.

IndexMaterial(index)

Adapt an existing glass law or a positive constant refractive index.

MaterialKerr([chi3, n2, at])

Declare a material's instantaneous isotropic Kerr response.

MaterialRegion(name, inner_radius, ...[, ...])

Assign one material and response list to an annular region.

PermittivityLaw(*args, **kwargs)

Describe an optical permittivity law independently of longitudinal paths.

class solprop.modes.material.GasKerr(fill)[source]#

Bases: Displayed

Declare a region’s gas fill as the source of its electronic cubic response.

Where MaterialKerr is one absolute chi3 the caller states, this is the fill’s own: each species’ optmat hyperpolarizability model at its number density, resolved by the run’s material selection (solprop.nonlinear.mixtures.electronic_response()). Under a carrier electronic policy the region’s response is the constant isotropic cubic of chi3 = sum_s N_s gamma3_s(lambda_0), the Kerr coefficient at the run’s carrier, as every other route evaluates a gas; under one of SEP 6’s dispersive policies it is each species’ dispersive cubic, the scalar kernel times the isotropic Kleinman tensor (docs/dev/seps/archive/sep-0006-dispersive-nonlinearity.md).

The fill is the region’s nonlinear medium only: the region’s linear law is its own material, as for every other region. A general modal guide has constant geometry, so every density of the fill must be constant along z.

Attributes:
fillsolprop.physdata.mixtures.Mixture

The gas: its species and their constant number densities, m^-3.

Raises:
ModeError

If a density of the fill varies along z.

Examples

>>> from solprop.modes.material import GasKerr
>>> from solprop.physdata import Mixture
>>> GasKerr(Mixture.fill({"Ar": 1.0}, 2.0)).fill.labels
('Ar',)
densities()[source]#

Return each population’s number density, in mixture order.

Returns:
tuple of float

Constant densities in m^-3.

fill: Mixture#
class solprop.modes.material.IndexMaterial(index)[source]#

Bases: object

Adapt an existing glass law or a positive constant refractive index.

The law of a general modal guide’s material region, which both providers this package ships solve without loss: an optmat index (OptmatGlass) is therefore held as its transparent approximation (lossless_index()), the counterpart a StepIndexMode of the same adapter holds, with the dropped k recorded for a run’s manifest (SEP 3, Q3). Any other glass is taken as it is.

Attributes:
indexGlassIndex or float

Optical refractive-index law, or positive dimensionless constant.

property identity: Mapping[str, JsonValue][source]#

Return the material model and its validity interval.

Returns:
collections.abc.Mapping

Serializable physical model and construction metadata.

index: GlassIndex | float#
property omega_domain: tuple[float, float][source]#

Return the validity interval in rad/s.

Returns:
tuple of float

Lower and upper angular frequency in rad/s.

permittivity(omega)[source]#

Evaluate the optical relative permittivity.

Parameters:
omegaarray_like

Positive frequencies in rad/s, shape (n_omega_permittivity,).

Returns:
numpy.ndarray

Complex relative permittivity, dimensionless, with the input shape.

Raises:
ModeError

If frequencies are malformed or outside the material domain.

type solprop.modes.material.JsonValue = bool | int | float | str | list[JsonValue] | dict[str, JsonValue] | None#

Anything solprop.output.schema.serialise() may return, and therefore anything JSON can carry. Re-exported by that module, which owns the file format.

solprop.modes.material.MEASURED_DIGITS = 6#

Significant digits a measured float keeps when it enters an identity.

A declared number – a radius, a chi3, a tolerance – is the one the caller wrote and enters an identity exactly. A measured one is the output of a dense solve and a reduction, so its last bits depend on the BLAS that did them: the same guide re-solved on another machine, or after a library update, gives a Gram defect and a profile error that differ in the last few digits and nothing else. Six digits is far more than any of them is accurate to (they are tolerances of order 1e-5 gated against budgets of order 1e-4) and far coarser than the spread a re-solve can produce, so quantising to it makes a resume key and a reconstruction gate compare equal for a run that did not change.

class solprop.modes.material.MaterialKerr(chi3=None, n2=None, at=None)[source]#

Bases: Displayed

Declare a material’s instantaneous isotropic Kerr response.

The nonlinear half of a MaterialRegion: the region owns its response and the general modal route reads it from there (solprop.translate.responses.regional_responses()), rather than taking a response list beside the guide. It is the absolute susceptibility of a condensed material, not a per-particle hyperpolarisability: a general guide carries no density path and the route’s density is the dimensionless one.

Give one of chi3 and n2. chi3 is used as it stands. n2 is converted with chi3 = 4 eps0 c n_0^2 n_2 / 3 (solprop.physdata.nonlinear_data.chi3_from_n2()), where n_0 is the region’s own linear index at the wavelength the n2 was measured at, and the result is then constant across the band, which is what the compiled per-region response carries.

An ``n2`` declares its wavelength. at= is that wavelength in metres – the one the published number was measured at, 1550 nm for a telecom fibre figure and 800 nm for most gas measurements – and it is where the linear index of the conversion is read. at=None, the default, reads it at the frequency the caller asks for, which in a run is the run’s own reference frequency. The two differ: a silica n2 declared at 800 nm and at 2 um give chi3 values 2.13 % apart, the square of the index ratio, and nothing downstream can tell them apart afterwards because the leaf carries one number. A region whose index varies appreciably across the run’s active band is therefore refused an n2 with no at by solprop.translate.general.general_modal_route(), rather than converted at a frequency nobody declared.

The region’s own law governs the conversion, and not the index the channels were solved with: the conversion asks MaterialRegion.material for its permittivity and nothing else. The two must therefore be the same material, which solprop.modes.guide.StepIndexProvider checks at construction against solprop.modes.guide.MATERIAL_AGREEMENT_RTOL – a core region declared at 2.0 beside channels solved at 1.45 would otherwise convert a declared n2 to a chi3 90 % too large.

Attributes:
chi3float or None

Absolute third-order susceptibility in m²/V², finite and non-negative; None when n2 is given.

n2float or None

Nonlinear index in m²/W in the convention where an intensity I shifts the refractive index by n2 I, finite and non-negative; None when chi3 is given.

atfloat or None

Wavelength in m the n2 was measured at, positive and finite, which is where the linear index of the conversion is read. None reads it at the frequency asked for. Refused beside chi3, which is absolute and declares no measurement wavelength.

Raises:
ModeError

If neither or both coefficients are given, one is negative or not finite, at is not positive and finite, or at is given beside chi3.

Examples

>>> from solprop.modes.material import IndexMaterial, MaterialKerr
>>> from solprop.physdata import fused_silica
>>> silica = IndexMaterial(fused_silica())
>>> f"{MaterialKerr(chi3=2.2e-22).susceptibility(silica, 2.3e15):.4e}"
'2.2000e-22'
>>> f"{MaterialKerr(n2=2.6e-20).susceptibility(silica, 2.3e15):.4e}"
'1.9438e-22'
>>> f"{MaterialKerr(n2=2.6e-20, at=1550e-9).susceptibility(silica, 2.3e15):.4e}"
'1.9198e-22'
at: float | None = None#
chi3: float | None = None#
n2: float | None = None#
nonlinear_index(material, omega)[source]#

Return the nonlinear index at one frequency, whichever was declared.

Parameters:
materialPermittivityLaw

The region’s own law, which supplies the linear index.

omegafloat

Positive angular frequency in rad/s inside the material’s domain, at which a declared chi3 is converted back.

Returns:
float

n2 in m²/W, non-negative. A declared n2 is returned as it stands, at the wavelength it declares.

Raises:
ModeError

If the frequency is not positive and finite, or the material’s index there is not a positive real number.

susceptibility(material, omega)[source]#

Return the absolute third-order susceptibility at one frequency.

Parameters:
materialPermittivityLaw

The region’s own law, which supplies the linear index the n2 conversion needs. Unused when chi3 was declared.

omegafloat

Positive angular frequency in rad/s inside the material’s domain, at which the conversion is made when the response declares no at.

Returns:
float

chi3 in m²/V², non-negative.

Raises:
ModeError

When n2 was declared and the frequency is not positive and finite, the declared at lies outside the material’s own domain, or the material’s index there is not a positive real number. A declared chi3 is returned without touching material or omega and raises nothing.

class solprop.modes.material.MaterialRegion(name, inner_radius, outer_radius, material, responses=())[source]#

Bases: Displayed

Assign one material and response list to an annular region.

Attributes:
namestr

Non-empty region name.

inner_radiusfloat or ZProfile

Non-negative inner radius in m, possibly following a declared path.

outer_radiusfloat or ZProfile or None

Outer radius in m; None denotes the unbounded exterior.

materialPermittivityLaw

Relative permittivity and immutable material identity.

responsestuple of MaterialKerr, GasKerr or SilicaTensorResponse

The region’s own declared physical responses, at most one of each kind and one electronic response, MaterialKerr or GasKerr. Empty declares a linear region: its nodes have no polarisation, which is how a linear cladding is said to be linear. A SilicaTensorResponse beside the MaterialKerr makes the region’s response the standard fibre pair, 1 - f_R instantaneous and f_R delayed, of one chi3.

property gas: GasKerr | None[source]#

Return the region’s gas fill response, or None.

Returns:
GasKerr or None

The one declared gas fill, or None.

inner_radius: float | ZProfile#
property kerr: MaterialKerr | None[source]#

Return the region’s declared Kerr response, or None if it is linear.

Returns:
MaterialKerr or None

The one declared instantaneous response, or None.

material: PermittivityLaw#
name: str#
outer_radius: float | ZProfile | None#
property raman: SilicaTensorResponse | None[source]#

Return the region’s declared delayed response, or None.

Returns:
solprop.nonlinear.raman.SilicaTensorResponse or None

The one declared delayed response, or None.

responses: tuple[MaterialResponse, ...] = ()#
type solprop.modes.material.MaterialResponse = MaterialKerr | GasKerr | SilicaTensorResponse#

What a material region may declare: the instantaneous cubic, the delayed tensor.

At most one of each kind, and one electronic response: MaterialKerr, which carries the region’s absolute chi3, or GasKerr, its gas fill’s. SilicaTensorResponse takes the share f_R of a MaterialKerr’s chi3 and leaves 1 - f_R to the instantaneous term, so a region that declares the delayed response without one has no susceptibility to share and is refused by name.

class solprop.modes.material.PermittivityLaw(*args, **kwargs)[source]#

Bases: Protocol

Describe an optical permittivity law independently of longitudinal paths.

Named for the law rather than for a material, because solprop.optics.Material is a length of a real medium in the flat solprop.sol namespace and the two must not be confused.

property identity: Mapping[str, JsonValue][source]#

Return the material state and source identity.

property omega_domain: tuple[float, float][source]#

Return the material validity interval in rad/s.

permittivity(omega)[source]#

Evaluate relative permittivity in the optics convention.

Parameters:
omegaarray_like

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

Returns:
numpy.ndarray

Dimensionless complex permittivity with the same shape.

solprop.modes.material.quantised_measurement(value)[source]#

Return a measured float rounded to MEASURED_DIGITS significant digits.

For the identities a modal run records (its resume key and reconstruction gate): what is measured is quantised before it is recorded, so that a re-translation of the same guide does not refuse a resume it should accept. What is declared is never passed through here.

Parameters:
valuefloat

The measured quantity, of any magnitude; nan and the infinities pass through unchanged.

Returns:
float

The same number to six significant digits.

Examples

>>> from solprop.modes.material import quantised_measurement
>>> quantised_measurement(3.768575004590464e-05)
3.76858e-05
>>> quantised_measurement(0.0)
0.0
>>> quantised_measurement(float("inf"))
inf