solprop.profiles#
Scalar paths along the propagation axis, with breakpoints and derivatives.
A ZProfile is a scalar function of z: the gas density in a pressure
gradient, the core radius of a taper, a pre-ionisation fraction. The cumulative
linear operator is built by resolving these paths first and taking the union of the
edges they produce as the mandatory split of the expensive array-valued operator
(solprop.translate.chebyshev.build_from_paths(), docs/dev/stepper.md section
4), so a profile has to offer three things:
vectorised evaluation, because the builder samples at Chebyshev points in blocks;
declared breakpoints, because a stage boundary is a hard kink that the adaptive split must never straddle and the stepper must land on;
an analytic derivative where one exists, and an honest declaration where it does not, so that a caller can tell a converged quantity from a differenced one.
A profile is directly usable as a path: build_from_paths([profile], ...) works
through __call__, and the caller passes the union of the profiles’ breakpoints
as mandatory_breakpoints.
Pressures are in bar at this interface, the one documented departure from SI
(docs/dev/conventions.md section 1); positions are in metres and densities in m^-3.
Vacuum ends. The steady-flow fill \(p(z) = \sqrt{p_0^2 + (z/L)(p_1^2 - p_0^2)}\) has
\(\mathrm{d}p/\mathrm{d}z = (p_1^2 - p_0^2)/(2Lp)\), which diverges where
\(p \to 0\). A fill that reaches exactly zero therefore caps every integration
scheme at about third order however small the step (docs/dev/stepper.md section 10,
trap 5), silently. PressureGradient refuses such a stage end and substitutes a
small floor, logging what it did; the floor is relative to the highest pressure of the
fill, so it behaves the same for a 0.8 bar gradient and a 40 bar one. A fill built by
solprop.gasflow.steady_fill() from the gas and the bore replaces a vacuum end by
its choked pressure instead, which is physical rather than numerical.
Tapers. Given the core radius, PressureGradient makes \(p^2\) linear in the
hydraulic resistance \(\int a^{-4}\,\mathrm{d}z\) rather than in z (Pennetta et
al., APL Photonics 4, 056105 (2019), eq. 6), so a narrow waist carries most of the
pressure drop; hydraulic_integral() evaluates that resistance.
Module Attributes
Default vacuum-end pressure floor, as a fraction of the highest stage pressure. |
|
Smallest highest-stage pressure a fill accepts, bar. |
Functions
|
Coerce a number to a constant path, and pass a path through unchanged. |
|
Return the hydraulic resistance |
|
Return the structural identity of a path, exact to the last bit. |
Classes
|
A path that does not vary along z. |
|
The number density along z of a gas following a pressure path. |
|
An arbitrary vectorised path, with its breakpoints declared by the caller. |
|
A path varying linearly between two ends and constant outside them. |
|
The monotone structure of a path over a closed interval. |
|
A path linear between given positions and constant outside them. |
|
A steady-flow pressure fill, in bar, with every stage boundary a breakpoint. |
|
Multiply a path and its derivative by a constant. |
|
A smooth function of another path, |
|
Add compatible paths in their declared order. |
|
A scalar path along the propagation axis. |
- class solprop.profiles.Constant(value, span=(0.0, inf))[source]#
Bases:
objectA path that does not vary along z.
- Attributes:
- valuefloat
The constant value, in whatever unit the consumer expects.
- spantuple of float
The interval in m the path is declared over. The default covers any propagation, since a constant needs no domain.
Examples
>>> import numpy as np >>> from solprop.profiles import Constant >>> radius = Constant(125e-6) >>> radius(np.array([0.0, 1.0])) array([0.000125, 0.000125]) >>> radius.derivative(np.array([0.5])) array([0.])
- property breakpoints: Float[ndarray, 'n_breakpoints'][source]#
Return the interval edges, which for a constant are none.
- Returns:
- numpy.ndarray
An empty array: a constant has no kinks.
- derivative(z)[source]#
Return zero at each position.
- Parameters:
- znumpy.ndarray
Positions in m, shape
(n_z,).
- Returns:
- numpy.ndarray
Zeros of shape
(n_z,).
- property derivative_is_analytic: bool[source]#
Return whether the derivative is exact.
- Returns:
- bool
Always
True: the derivative is identically zero.
- property is_constant: bool[source]#
Return whether the path is the same everywhere.
- Returns:
- bool
Always
True.
- property jumps: Float[ndarray, 'n_jumps'][source]#
Return the declared discontinuities, which for a constant are none.
- Returns:
- numpy.ndarray
Positions in m.
- solprop.profiles.DEFAULT_PRESSURE_FLOOR_FRACTION: Final = 0.0001#
Default vacuum-end pressure floor, as a fraction of the highest stage pressure.
At 1e-4 of the peak the residual gas contributes a relative refractivity of 1e-4 of the fill – nothing, for a gradient whose point is that the end is empty – while the slope of the steady-flow profile stays finite and cheap for the adaptive Chebyshev split to resolve. Being relative rather than absolute, it means the same thing for a 0.8 bar gradient as for a 40 bar one.
- class solprop.profiles.DensityPath(gas, pressure, temperature=293.15)[source]#
Bases:
DisplayedThe number density along z of a gas following a pressure path.
The equation of state is a scalar call into optmat (CoolProp) that costs about a millisecond, and the Chebyshev builder samples a path thousands of times, so the density is tabulated once over the pressure range the path spans and interpolated with a cubic spline. The spline’s derivative is exact, so
d(rho)/dz = rho'(p) dp/dzstays analytic whenever the pressure path is.A temperature that varies along z makes the density
rho(p(z), T(z)). The compressibility factorZ(p, T) = p / (rho k_B T)is then tabulated as a tensor Chebyshev series over the rectangle of pressures and temperatures the two paths span, converged to 1e-13 on each axis (a few hundred equation-of-state calls, fewer than the constant-temperature spline’s 1024), andrho = p / (k_B T Z)keeps its ideal-gas part exact. The derivative isrho_p p' + rho_T T'with the series’ exact partial derivatives. A constant temperature, a number or a constant path, takes the spline above, bit for bit.- Attributes:
- gasGas or str or Species
The species: a built-in gas’s name takes optmat’s equation of state, a species its own.
- pressureZProfile
The pressure path in bar.
- temperaturefloat or ZProfile
Temperature in K, > 0: a number, or a path along z. A constant path is stored as its value.
Examples
>>> import numpy as np >>> from solprop.physdata import Gas >>> from solprop.profiles import DensityPath, Linear, PressureGradient >>> fill = PressureGradient.two_point(1.0, 1.0, 0.5) >>> path = DensityPath(Gas.He, fill) >>> f"{float(path(np.array([0.0]))[0]):.6e}" '2.469537e+25' >>> bool(path.derivative(np.array([0.5]))[0] < 0.0) True >>> warm = DensityPath(Gas.He, fill, Linear(293.15, 350.0, 1.0)) >>> f"{float(warm(np.array([0.0]))[0]):.6e}" '2.469537e+25'
- property breakpoints: Float[ndarray, 'n_breakpoints'][source]#
Return the breakpoints of the pressure path, and of a temperature path.
- Returns:
- numpy.ndarray
The positions in m; the density kinks exactly where the pressure or the temperature does.
- derivative(z)[source]#
Return the density gradient at each position.
- Parameters:
- znumpy.ndarray
Positions in m, shape
(n_z,).
- Returns:
- numpy.ndarray
d(rho)/dzin m^-3 per metre, by the chain rule through the pressure path, and through a temperature pathrho_p p' + rho_T T'.
- property derivative_is_analytic: bool[source]#
Return whether the derivative is exact.
- Returns:
- bool
Truewhen the pressure path’s derivative is, and a temperature path’s: the tables contribute exact derivatives of their interpolants.
- property is_constant: bool[source]#
Return whether the density never varies.
- Returns:
- bool
Truewhen the pressure never varies and neither does the temperature, or the pressure is identically zero.
- property jumps: Float[ndarray, 'n_jumps'][source]#
Return the declared discontinuities of the pressure and temperature paths.
- Returns:
- numpy.ndarray
Positions in m; the density jumps only where an argument does.
- variation(start, end)[source]#
Enclose the variation through the pressure path’s monotone pieces.
The density is the tabulated cubic spline of the pressure. On a monotone pressure piece the density is monotone between the spline’s critical points in the piece’s pressure range, which are the real roots of its piecewise quadratic derivative, found in closed form; the variation is then exact from the values there. A pressure piece not certified monotone is bounded by the spline’s largest slope on its range times the pressure variation.
- Parameters:
- start, endfloat
The closed interval in m, finite with
start < end.
- Returns:
- PathVariation
The record of the tabulated density, constant outside the span.
- Raises:
- TranslationError
If the temperature varies along z: that two-dimensional table has no enclosure here, and the spatial routes do not carry one.
- class solprop.profiles.FromCallable(func, span, kinks=<factory>, slope=None, jumps=<factory>, turning=None)[source]#
Bases:
objectAn arbitrary vectorised path, with its breakpoints declared by the caller.
The escape hatch for a measured or exotic profile. Because the adaptive Chebyshev split finds smooth structure but cannot see a kink it was not told about, the breakpoints are a required argument rather than something guessed.
With no slope the derivative is a Richardson-extrapolated central difference,
derivative_is_analyticisFalse, and a caller that needs an analyticbeta_1(ADR-006) must supply one.An arbitrary callable has no knowable variation: sampling it, or its derivative, at finitely many points proves nothing between them. A caller that needs one (the adiabatic certificate of
solprop.adiabatic) declares it: turning lists every position where the path may change direction, so that it is monotone between consecutive members of the span’s ends, turning, kinks and jumps. Without that declarationvariation()refuses.- Attributes:
- funccollections.abc.Callable
The path, vectorised over an array of positions in m.
- spantuple of float
The interval in m the path is defined over, as
(start, end).- kinksnumpy.ndarray
Positions in m where the path kinks, strictly increasing. May be empty.
- slopecollections.abc.Callable or None
The analytic derivative, if there is one.
- jumpsnumpy.ndarray
Positions in m strictly inside the span where the path is discontinuous, strictly increasing. The callable’s value at a jump is its limit from the right, and the limit from the left is its value at the next float below. May be empty; every jump is also a breakpoint.
- turningnumpy.ndarray or None
Declared positions in m, inside the span and strictly increasing, where the path may turn;
None(the default) declares nothing and leaves the variation unknown.
Examples
>>> import numpy as np >>> from solprop.profiles import FromCallable >>> path = FromCallable(np.sin, (0.0, 1.0), slope=np.cos) >>> path.derivative_is_analytic True >>> bool(abs(path.derivative(np.array([0.3]))[0] - np.cos(0.3)) < 1e-15) True
- property breakpoints: Float[ndarray, 'n_breakpoints'][source]#
Return the declared kinks and jumps.
- Returns:
- numpy.ndarray
The positions in m, sorted and unique.
- derivative(z)[source]#
Return the derivative at each position.
- Parameters:
- znumpy.ndarray
Positions in m, shape
(n_z,).
- Returns:
- numpy.ndarray
The analytic derivative when one was supplied, otherwise a Richardson-extrapolated central difference, whose relative accuracy is about 1e-10 for a smooth path and no better.
- property derivative_is_analytic: bool[source]#
Return whether the derivative is exact.
- Returns:
- bool
Trueonly when a slope was supplied.
- property is_constant: bool[source]#
Return whether the path is known to be constant.
- Returns:
- bool
Always
False: an arbitrary callable cannot be inspected, and the conservative answer only costs a re-evaluation.
- jumps: Float[ndarray, 'n_jumps']#
- kinks: Float[ndarray, 'n_kinks']#
- variation(start, end)[source]#
Return the variation the declaration fixes.
- Parameters:
- start, endfloat
The closed interval in m, inside the span, finite with
start < end.
- Returns:
- PathVariation
Monotone pieces between the declared positions, from the callable’s values and its one-sided limits at the jumps.
- Raises:
- TranslationError
If no turning points were declared, or the interval leaves the span, where the callable’s continuation is unknown.
- class solprop.profiles.Linear(start, end, length)[source]#
Bases:
DisplayedA path varying linearly between two ends and constant outside them.
A two-stage
PiecewiseLinear, named for the common case of a taper.- Attributes:
- startfloat
Value at
z = 0.- endfloat
Value at
z = length.- lengthfloat
Length of the varying section in m, > 0.
Examples
>>> import numpy as np >>> from solprop.profiles import Linear >>> taper = Linear(125e-6, 75e-6, 1.5) >>> taper(np.array([0.0, 0.75, 1.5])) * 1e6 array([125., 100., 75.])
- property breakpoints: Float[ndarray, 'n_breakpoints'][source]#
Return the two ends of the varying section.
- Returns:
- numpy.ndarray
[0, length]in m.
- derivative(z)[source]#
Return the slope at each position.
- Parameters:
- znumpy.ndarray
Positions in m, shape
(n_z,).
- Returns:
- numpy.ndarray
(end - start) / lengthinside the section and zero outside.
- property derivative_is_analytic: bool[source]#
Return whether the derivative is exact.
- Returns:
- bool
Always
True.
- property is_constant: bool[source]#
Return whether the two ends carry the same value.
- Returns:
- bool
Truewhenstart == end.
- property jumps: Float[ndarray, 'n_jumps'][source]#
Return the declared discontinuities, which for a linear path are none.
- Returns:
- numpy.ndarray
Positions in m.
- variation(start, end)[source]#
Return the exact variation of the two-stage table.
- Parameters:
- start, endfloat
The closed interval in m, finite with
start < end.
- Returns:
- PathVariation
The record of the equivalent
PiecewiseLinear.
- solprop.profiles.MIN_STAGE_PRESSURE: Final = 1e-150#
Smallest highest-stage pressure a fill accepts, bar.
The steady-flow profile is linear in
p^2and its slope divides byp, so every pressure the fill evaluates – the default floor ofDEFAULT_PRESSURE_FLOOR_FRACTIONtimes the highest stage included – must square to a normal float.(1e-4 * 1e-150)^2 = 1e-308is the smallest normal double; below this the floored end squares to zero and the slope there is infinite. Found by hypothesis: a fill from 0 to 6.5e-159 bar passed the old exact-zero guard and returned an infinite derivative at the entrance.
- class solprop.profiles.PathVariation(knots, first, last, variation, low, high, monotone)[source]#
Bases:
objectThe monotone structure of a path over a closed interval.
The interval is cut at knots into pieces. On each open piece the path is continuous; its one-sided limits at the piece’s ends are first and last, its values lie in
[low, high]and its total variation inside the piece is at most variation. Where monotone holds the path is monotone on the piece andvariation == abs(last - first)exactly. A difference between one piece’s last and the next piece’s first is a declared jump.The record describes the represented path, the function the class evaluates, not a physical profile it may approximate; an interpolation error is a separate envelope.
- Attributes:
- knotsnumpy.ndarray
Piece edges in m, strictly increasing, at least two.
- first, lastnumpy.ndarray
Limits of the path at each piece’s start from the right and at its end from the left, shape
(n_pieces,).- variationnumpy.ndarray
Upper bound of the total variation inside each open piece, at least
abs(last - first).- low, highnumpy.ndarray
Lower and upper bounds of the path on each closed piece, limits included.
- monotonenumpy.ndarray
Whether each piece is certified monotone, so that its variation is exact.
- Raises:
- TranslationError
If the arrays are inconsistent or the bounds do not enclose the limits.
Examples
>>> from solprop.profiles import PiecewiseLinear >>> path = PiecewiseLinear.from_stages([0.0, 1.0, 2.0], [0.0, 2.0, 1.0]) >>> record = path.variation(0.0, 2.0) >>> float(record.total_variation) 3.0 >>> record.jumps.size 0
- collapse()[source]#
Return the same enclosure as one piece over the whole interval.
- Returns:
- PathVariation
One piece whose variation includes every interior jump; it is monotone only when every piece is, no jump reverses, and all move one way.
- first: Float[ndarray, 'n_pieces']#
- high: Float[ndarray, 'n_pieces']#
- property jumps: Float[ndarray, 'n_jumps'][source]#
Return the interior knots where the path jumps.
- Returns:
- numpy.ndarray
Positions in m where the next piece’s first differs from last.
- knots: Float[ndarray, 'n_knots']#
- last: Float[ndarray, 'n_pieces']#
- low: Float[ndarray, 'n_pieces']#
- monotone: Bool[ndarray, 'n_pieces']#
- scaled(factor)[source]#
Return the enclosure of the path multiplied by a constant.
- Parameters:
- factorfloat
Finite multiplier.
- Returns:
- PathVariation
The scaled record; a negative factor swaps the bounds.
- property total_variation: float[source]#
Return the enclosed total variation over the whole interval.
- Returns:
- float
The sum of the pieces’ variations and the jumps’ magnitudes, in the unit of the path.
- variation: Float[ndarray, 'n_pieces']#
- class solprop.profiles.PiecewiseLinear(positions, values)[source]#
Bases:
DisplayedA path linear between given positions and constant outside them.
Every position is a breakpoint, because the slope jumps there. Clamping outside the declared range rather than extrapolating keeps the path bounded when the Chebyshev table is built slightly beyond the fibre end.
- Attributes:
- positionsnumpy.ndarray
Stage boundaries in m, strictly increasing, at least two.
- valuesnumpy.ndarray
The value at each position.
Examples
>>> import numpy as np >>> from solprop.profiles import PiecewiseLinear >>> taper = PiecewiseLinear.from_stages([0.0, 1.0], [125e-6, 75e-6]) >>> taper(np.array([0.0, 0.5, 1.0, 2.0])) * 1e6 array([125., 100., 75., 75.]) >>> taper.derivative(np.array([0.5])) * 1e6 array([-50.])
- property breakpoints: Float[ndarray, 'n_breakpoints'][source]#
Return the stage boundaries, every one of which is a kink.
- Returns:
- numpy.ndarray
The positions, in m.
- derivative(z)[source]#
Return the slope at each position.
The value at a breakpoint is the slope of the stage that starts there, and zero outside the declared range; the one-sided choice is arbitrary at a kink and the Chebyshev builder never samples one, because a breakpoint is an interval edge.
- Parameters:
- znumpy.ndarray
Positions in m, shape
(n_z,).
- Returns:
- numpy.ndarray
d(value)/dzper metre, shape(n_z,).
- property derivative_is_analytic: bool[source]#
Return whether the derivative is exact.
- Returns:
- bool
Always
True.
- classmethod from_stages(positions, values)[source]#
Build a path from any sequence of positions and values.
- Parameters:
- positionsarray_like
Stage boundaries in m, strictly increasing, at least two.
- valuesarray_like
The value at each position.
- Returns:
- PiecewiseLinear
The path.
Examples
>>> from solprop.profiles import PiecewiseLinear >>> PiecewiseLinear.from_stages([0.0, 1.0], [1.0, 3.0]).values array([1., 3.])
- property is_constant: bool[source]#
Return whether every stage carries the same value.
- Returns:
- bool
Truewhen the path never varies.
- property jumps: Float[ndarray, 'n_jumps'][source]#
Return the declared discontinuities, none for a continuous interpolant.
- Returns:
- numpy.ndarray
Positions in m.
- positions: Float[ndarray, 'n_positions']#
- values: Float[ndarray, 'n_values']#
- class solprop.profiles.PressureGradient(positions, pressures, floor, radius=None, choked_ends=(False, False), weight=None)[source]#
Bases:
DisplayedA steady-flow pressure fill, in bar, with every stage boundary a breakpoint.
Laminar flow of a compressible gas through a narrow tube of constant bore makes \(p^2\) linear in
z, so between two stage ends\[p(z) = \sqrt{p_i^2 + \frac{z - z_i}{z_{i+1} - z_i}(p_{i+1}^2 - p_i^2)}\]evaluated as the convex combination \(\sqrt{(1-f)\,p_i^2 + f\,p_{i+1}^2}\), which cannot cancel, and the pressure is held constant outside the declared range. The derivative \(\mathrm{d}p/\mathrm{d}z = (p_{i+1}^2 - p_i^2)/(2\,\Delta z\,p)\) is exact.
Given a varying core radius \(a(z)\), the mass flow of an isothermal ideal gas in Poiseuille flow, \(\dot m \propto a^4\,p\,\mathrm{d}p/\mathrm{d}z\), is constant along each stage, so \(p^2\) is linear in the hydraulic resistance instead (Pennetta et al., APL Photonics 4, 056105 (2019), eq. 6):
\[p^2 = (1 - f)\,p_i^2 + f\,p_{i+1}^2, \quad f(z) = \frac{R(z_i, z)}{R(z_i, z_{i+1})}, \quad R(u, v) = \int_u^v a^{-4}\,\mathrm{d}z,\]with \(\mathrm{d}p/\mathrm{d}z = (p_{i+1}^2 - p_i^2)\,a^{-4}/(2 R p)\), still analytic. Every stage is an independent flow between two gas cells. A constant or omitted radius is the uniform law above, bit for bit.
A gas whose temperature varies along the fibre carries the mass flow \(\dot m \propto (p/T)\,a^4\,\mathrm{d}p/\mathrm{d}z/\eta(T)\), so the integrand of \(R\) becomes \(w\,a^{-4}\) with the flow weight \(w = \eta(T)\,T\), which
solprop.gasflow.steady_fill()builds from the gas’s viscosity; the fill itself needs only its variation, since a constant factor cancels from \(f\). A constant or omitted weight is the law above, bit for bit.A stage pressure of zero makes that derivative infinite and caps every integration scheme at about third order (
docs/dev/stepper.mdsection 10, trap 5). Such a pressure is raised to floor and the substitution is logged. Passingfloor=0.0keeps the true vacuum end, for reproducing a result that assumes one, and logs a stronger warning. A physical vacuum end is choked rather than floored: build the fill withsolprop.gasflow.steady_fill(), which knows the gas.- Attributes:
- positionsnumpy.ndarray
Stage boundaries in m, strictly increasing, at least two.
- pressuresnumpy.ndarray
Absolute pressure in bar at each boundary, >= 0, after any flooring.
- floorfloat
The pressure floor in bar that was applied.
- radiusZProfile or None
The core radius in m the flow follows, or
Nonefor a uniform bore. A constant radius is stored asNone: it is the uniform law exactly.- choked_endstuple of bool
Whether the first and the last end pressure is a choked pressure set by
solprop.gasflow.steady_fill(), which depends on the gas;(False, False)for a fill whose ends are the declared ones.- weightZProfile or None
The flow weight multiplying
a^-4in the resistance, positive, in any unit (eta(T) Tin Pa s K for a temperature path), orNonefor none. A constant weight is stored asNone: it cancels exactly.
Examples
>>> import numpy as np >>> from solprop.profiles import PressureGradient >>> fill = PressureGradient.two_point(1.5, 0.8, 0.0) >>> float(fill.floor) 8e-05 >>> [f"{value:.4f}" for value in fill(np.array([0.0, 0.75, 1.5]))] ['0.8000', '0.5657', '0.0001'] >>> fill.breakpoints array([0. , 1.5])
- property breakpoints: Float[ndarray, 'n_breakpoints'][source]#
Return the stage boundaries and the bore’s kinks, every one a hard kink.
- Returns:
- numpy.ndarray
The positions in m: the stage boundaries, joined for a fill that follows a varying bore or carries a flow weight by their breakpoints inside the fill, where the slope of the pressure kinks with theirs.
- derivative(z)[source]#
Return the pressure gradient in bar per metre at each position.
- Parameters:
- znumpy.ndarray
Positions in m, shape
(n_z,).
- Returns:
- numpy.ndarray
dp/dz = (p_next^2 - p^2) / (2 dz p)on a uniform bore and(p_next^2 - p^2) w a^-4 / (2 R p)on a varying one or with a flow weightw, and zero outside the fill. It is infinite at a stage end held at exactly zero pressure, which is why the constructor floors one by default.
- property derivative_is_analytic: bool[source]#
Return whether the derivative is exact.
- Returns:
- bool
Always
True.
- classmethod from_stages(positions, pressures, *, floor=None, radius=None, weight=None)[source]#
Build a multi-stage fill, applying and logging the vacuum-end floor.
- Parameters:
- positionsarray_like
Stage boundaries in m, strictly increasing, at least two.
- pressuresarray_like
Absolute pressure in bar at each boundary, >= 0.
- floorfloat or None, optional
Smallest pressure in bar any stage end may take.
NoneusesDEFAULT_PRESSURE_FLOOR_FRACTIONof the highest stage pressure;0.0keeps a true vacuum end and logs that the order of the scheme is then capped.- radiusfloat, ZProfile or None, optional
Core radius in m, > 0, which the flow follows (the class docstring);
Noneor a constant is the uniform bore. A radius that is neither constant nor linear between its breakpoints is integrated by Chebyshev interpolation and refused if that does not converge.- weightfloat, ZProfile or None, optional
Flow weight multiplying
a^-4, > 0 (the class docstring), integrated with the bore by Chebyshev interpolation;Noneor a constant is none.
- Returns:
- PressureGradient
The fill, with any pressure below floor raised to it.
- Raises:
- TranslationError
If the stage table is invalid, floor is negative, every stage pressure is zero, the highest is too small for its square to be representable, or the radius is not positive or cannot be integrated.
Examples
>>> from solprop.profiles import PressureGradient >>> fill = PressureGradient.from_stages([0.0, 0.6, 1.0], [0.0, 5.0, 0.0]) >>> fill.pressures array([5.e-04, 5.e+00, 5.e-04])
- property is_constant: bool[source]#
Return whether every stage carries the same pressure.
- Returns:
- bool
Truewhen the fill never varies.
- property jumps: Float[ndarray, 'n_jumps'][source]#
Return the declared discontinuities, which for a steady-flow fill are none.
- Returns:
- numpy.ndarray
Positions in m.
- positions: Float[ndarray, 'n_positions']#
- pressures: Float[ndarray, 'n_pressures']#
- classmethod two_point(length, start_bar, end_bar, *, floor=None, radius=None, weight=None)[source]#
Build a single-stage fill from one end pressure to the other.
- Parameters:
- lengthfloat
Length of the fill in m, > 0.
- start_bar, end_barfloat
Absolute pressures in bar at
z = 0andz = length, >= 0.- floorfloat or None, optional
Smallest pressure in bar any stage end may take.
NoneusesDEFAULT_PRESSURE_FLOOR_FRACTIONof the highest stage pressure.- radiusfloat, ZProfile or None, optional
Core radius in m, > 0, which the flow follows;
Noneor a constant is the uniform bore.- weightfloat, ZProfile or None, optional
Flow weight multiplying
a^-4, > 0 (the class docstring);Noneor a constant is none.
- Returns:
- PressureGradient
The fill.
- Raises:
- TranslationError
If the length is not positive, or a pressure is negative.
Examples
>>> from solprop.profiles import PressureGradient >>> PressureGradient.two_point(1.0, 2.0, 2.0).pressures array([2., 2.])
- variation(start, end)[source]#
Return the exact variation: the fill is monotone on every stage.
On a stage
p^2is the convex combination of its end values with the weightf, andfis the running hydraulic resistance over its total: the integral of a positive weight, so increasing. The pressure therefore runs monotonically from one stage pressure to the next, and the bore’s own kinks never turn it.- Parameters:
- start, endfloat
The closed interval in m, finite with
start < end.
- Returns:
- PathVariation
One monotone piece per stage inside the interval, and flat pieces outside the fill.
- class solprop.profiles.Scaled(path, factor)[source]#
Bases:
objectMultiply a path and its derivative by a constant.
- Attributes:
- pathZProfile
Underlying path, with its units and endpoint continuation.
- factorfloat
Finite multiplier; the output units include those of this multiplier.
- property breakpoints: Float[ndarray, 'n_breakpoints'][source]#
Return the underlying breakpoints in m.
- Returns:
- numpy.ndarray
Positions of derivative discontinuities.
- derivative(z)[source]#
Evaluate the scaled derivative.
- Parameters:
- znumpy.ndarray
Positions in m.
- Returns:
- numpy.ndarray
Scaled derivatives per metre, with the input shape.
- property derivative_is_analytic: bool[source]#
Return whether the underlying derivative is analytic.
- Returns:
- bool
The underlying path’s declaration.
- property is_constant: bool[source]#
Return whether the scaled path is constant.
- Returns:
- bool
True for a constant path or a zero multiplier.
- property jumps: Float[ndarray, 'n_jumps'][source]#
Return the underlying declared discontinuities in m.
- Returns:
- numpy.ndarray
Positions where the path jumps.
- class solprop.profiles.SeriesOfPath(path, series)[source]#
Bases:
DisplayedA smooth function of another path,
f(g(z)), withfa Chebyshev series.The steady-flow fill of a gas whose temperature varies along the fibre is weighted by
eta(T) T(PressureGradient):solprop.gasflow.steady_fill()represents that weight as a converged Chebyshev series in the temperature, evaluated on the temperature path. The derivativef'(g) g'is analytic whenever the inner path’s is.- Attributes:
- pathZProfile
The inner path
g, in whatever unit series takes.- seriesnumpy.polynomial.Chebyshev
The outer function
f, with its domain in the unit of path; outside the domain it extrapolates, so it should cover the path’s range.
Examples
>>> import numpy as np >>> from numpy.polynomial import Chebyshev >>> from solprop.profiles import Linear, SeriesOfPath >>> square = Chebyshev.fit([1.0, 2.0, 3.0], [1.0, 4.0, 9.0], 2, domain=[1.0, 3.0]) >>> weight = SeriesOfPath(Linear(1.0, 3.0, 2.0), square) >>> [round(float(v), 12) for v in weight(np.array([0.0, 1.0]))] [1.0, 4.0] >>> round(float(weight.derivative(np.array([1.0]))[0]), 12) 4.0
- property breakpoints: Float[ndarray, 'n_breakpoints'][source]#
Return the inner path’s breakpoints.
- Returns:
- numpy.ndarray
The positions in m; a smooth function kinks where its argument does.
- derivative(z)[source]#
Return
f'(g(z)) g'(z)at each position.- Parameters:
- znumpy.ndarray
Positions in m, shape
(n_z,).
- Returns:
- numpy.ndarray
The slope per metre, shape
(n_z,).
- property derivative_is_analytic: bool[source]#
Return whether the derivative is exact.
- Returns:
- bool
Truewhen the inner path’s is: the series has an exact derivative.
- property is_constant: bool[source]#
Return whether the inner path is constant.
- Returns:
- bool
Truewhen the argument never varies.
- property jumps: Float[ndarray, 'n_jumps'][source]#
Return the inner path’s declared discontinuities.
- Returns:
- numpy.ndarray
Positions in m.
- variation(start, end)[source]#
Enclose the variation through the series’ critical points.
- Parameters:
- start, endfloat
The closed interval in m, finite with
start < end.
- Returns:
- PathVariation
The composite record: exact on a monotone inner piece between the series’ near-real critical points, otherwise the series’ derivative bound times the inner variation.
- Raises:
- TranslationError
If the inner path leaves the series’ domain, where it extrapolates.
- class solprop.profiles.Sum(paths)[source]#
Bases:
objectAdd compatible paths in their declared order.
- Attributes:
- pathstuple of ZProfile
Non-empty sequence of paths with compatible units. Their spans are joined; outside an individual span that path supplies its endpoint continuation.
- property breakpoints: Float[ndarray, 'n_breakpoints'][source]#
Return the union of the component breakpoints in m.
- Returns:
- numpy.ndarray
Sorted unique positions.
- derivative(z)[source]#
Evaluate the derivative sum in component order.
- Parameters:
- znumpy.ndarray
Positions in m.
- Returns:
- numpy.ndarray
Summed derivatives per metre with the input shape.
- property derivative_is_analytic: bool[source]#
Return whether every component derivative is analytic.
- Returns:
- bool
Conjunction of the component declarations.
- property is_constant: bool[source]#
Return whether every component is constant.
- Returns:
- bool
Conjunction of the component declarations.
- property jumps: Float[ndarray, 'n_jumps'][source]#
Return the union of the component discontinuities in m.
- Returns:
- numpy.ndarray
Sorted unique positions.
- variation(start, end)[source]#
Enclose the variation of the sum on the union of the component pieces.
On a piece where every component is certified monotone in the same direction the sum is monotone and its variation exact; otherwise the variation is at most the sum of the components’, the triangle inequality.
- Parameters:
- start, endfloat
The closed interval in m, finite with
start < end.
- Returns:
- PathVariation
The record on the union of the components’ knots.
- class solprop.profiles.ZProfile(*args, **kwargs)[source]#
Bases:
ProtocolA scalar path along the propagation axis.
Implementations are frozen dataclasses. Every one is callable on an array of positions and returns an array of the same shape, so that it can be handed straight to
solprop.translate.chebyshev.build_from_paths()as a path.- property breakpoints: Float[ndarray, 'n_breakpoints'][source]#
Return the positions in m where the path jumps or kinks, increasing.
- derivative(z)[source]#
Return the derivative of the path with respect to z at each position.
- Parameters:
- znumpy.ndarray
Positions along the waveguide in m, shape
(n_z,).
- Returns:
- numpy.ndarray
d(value)/dzper metre at each position, shape(n_z,).
- property derivative_is_analytic: bool[source]#
Whether
derivative()is exact rather than a finite difference.
- property jumps: Float[ndarray, 'n_jumps'][source]#
Return the declared discontinuities in m, a subset of the breakpoints.
- solprop.profiles.as_profile(value, span=(0.0, inf))[source]#
Coerce a number to a constant path, and pass a path through unchanged.
- Parameters:
- valuefloat or ZProfile
A constant value, or a path already.
- spantuple of float, optional
The interval in m given to a
Constantbuilt from a number.
- Returns:
- ZProfile
The path.
- Raises:
- TranslationError
If value is neither a real number nor a path.
Examples
>>> import numpy as np >>> from solprop.profiles import as_profile >>> as_profile(125e-6)(np.array([0.0, 2.0])) * 1e6 array([125., 125.])
- solprop.profiles.hydraulic_integral(radius, positions, *, weight=None)[source]#
Return the hydraulic resistance
int w a^-4 dzof each stage of a bore.The Poiseuille throughput of a stage is
pi (p_high^2 - p_low^2) / (16 eta R)withRthis integral without a weight:length / a^4for a uniform bore. A gas whose temperature varies along the fibre takes the weightw = eta(T) T(PressureGradient).- Parameters:
- radiusfloat or ZProfile
Core radius in m, > 0 over the stages.
- positionsarray_like
Stage boundaries in m, strictly increasing, at least two.
- weightfloat, ZProfile or None, optional
A flow weight multiplying
a^-4, > 0 over the stages, in any unit.None(the default) is no weight.
- Returns:
- numpy.ndarray
int_{z_i}^{z_{i+1}} w a^-4 dzin m^-3 times the unit of weight, one per stage.
- Raises:
- TranslationError
If the positions are invalid, or the radius or the weight is not positive or cannot be integrated.
Examples
>>> from solprop.profiles import Linear, hydraulic_integral >>> f"{hydraulic_integral(125e-6, [0.0, 1.0])[0]:.6e}" '4.096000e+15' >>> taper = hydraulic_integral(Linear(125e-6, 75e-6, 1.0), [0.0, 1.0]) >>> f"{taper[0]:.6e}" '1.238914e+16'
- solprop.profiles.profile_identity(profile)[source]#
Return the structural identity of a path, exact to the last bit.
Two paths give the same identity exactly when they are the same class built from the same numbers. Unlike
repr, the result does not depend onnumpy.set_printoptionsand does not summarise a long array, so a 1200-knotPiecewiseLinearis distinguished from any other. Every value is a string, an integer or a nested mapping of them, so the result is JSON-able and can go straight into a provider’sidentity.- Parameters:
- profilefloat or ZProfile
A constant value, or any path declared in this module.
- Returns:
- dict
{'kind': <class name>, ...}with the defining numbers as exact hexadecimal float literals and long arrays as SHA-256 digests.
- Raises:
- TranslationError
If the path is an arbitrary callable (
FromCallable) or an implementation this module does not know: neither has a structural identity, and arepris not one.
Examples
>>> from solprop.profiles import Linear, profile_identity >>> profile_identity(Linear(125e-6, 75e-6, 1.5))["kind"] 'Linear' >>> profile_identity(2.0) == profile_identity(2.0) True