solprop.grid#
Time and frequency grids for field-resolved and envelope propagation.
Two grids implement one protocol. FieldGrid carries a real field E(t) and
stores its one-sided spectrum; EnvelopeGrid carries a complex envelope A(t)
and stores the full spectrum in FFT order. Both carry an oversampled fine grid on
which nonlinear responses are evaluated, the masks that say which bins are physical, and
the Planck-taper collars that absorb what leaves the window.
The construction arithmetic, the invariants, the layout rules and the sign convention
are fixed by docs/dev/conventions.md §2-§3, and the manual page
docs/guide/setup/grids.md derives them. Four hazards are guarded against, each noted
where
it is handled: overlapping coarse spectral bins when the transform size is not a power
of two, a degenerate temporal collar when the realised window equals the requested one,
an envelope fine spacing that ignores the low-frequency edge, and an envelope crop that
is derived from the upper edge alone and then applied symmetrically.
Module Attributes
The transform-size rules of |
|
Width of each temporal collar, as a fraction of the realised window (SEP 21 D3). |
|
Where the temporal collar lies against the requested window. |
Functions
|
Return the modelled relative cost of a real transform of length n. |
|
Evaluate a Planck taper that rises then falls between four breakpoints. |
|
Evaluate the analytic derivative of |
|
Bound the absolute error of |
|
Suggest |
Classes
|
Geometry of one Planck-taper collar, as four breakpoints. |
|
Grid for propagation of a complex envelope about a carrier. |
|
Grid for field-resolved propagation of a real electric field. |
|
Construct a periodic Cartesian grid with x fastest in flattened columns. |
|
A starting point for a route's |
|
Construct a periodic line grid in x for a beam uniform in y, per metre of y. |
|
Construct an axisymmetric spatial grid, with room for a collar outside it. |
|
Shared state of the field and envelope grids. |
- class solprop.grid.Collar(zero_low, one_low, one_high, zero_high)[source]#
Bases:
objectGeometry of one Planck-taper collar, as four breakpoints.
A collar is where the propagation is absorbed rather than modelled: the spectral collar outside the requested wavelength limits, and the temporal collar outside the requested time window.
solprop.boundariesturns these profiles into absorber rates; here they define the profile itself.- Attributes:
- zero_lowfloat
Lower point at which the profile reaches 0.
- one_lowfloat
Lower point at which the profile reaches 1.
- one_highfloat
Upper point at which the profile leaves 1.
- zero_highfloat
Upper point at which the profile returns to 0.
Examples
>>> import numpy as np >>> from solprop.grid import Collar >>> collar = Collar(0.0, 1.0, 3.0, 4.0) >>> collar.window(np.array([0.5, 2.0])).round(3).tolist() [0.5, 1.0]
- property width_high: float[source]#
Return the width of the falling edge, in the collar’s own units.
- Returns:
- float
The distance from
one_hightozero_high.
- property width_low: float[source]#
Return the width of the rising edge, in the collar’s own units.
- Returns:
- float
The distance from
zero_lowtoone_low.
- window(x)[source]#
Evaluate the collar’s Planck taper at the given points.
- Parameters:
- xnumpy.ndarray
Points at which to evaluate the profile, shape
(n,).
- Returns:
- numpy.ndarray
Window values in
[0, 1], shape(n,).
- window_derivative(x)[source]#
Evaluate the analytic derivative of the collar’s profile.
- Parameters:
- xnumpy.ndarray
Points at which to evaluate it, shape
(n,).
- Returns:
- numpy.ndarray
d window / dxin reciprocal units ofx, shape(n,); seeplanck_taper_derivative().
- solprop.grid.CollarPlacement#
Where the temporal collar lies against the requested window.
alias of
Literal[‘outside’, ‘inside’]
- solprop.grid.DEFAULT_COLLAR_FRACTION: Final = 0.1#
Width of each temporal collar, as a fraction of the realised window (SEP 21 D3).
- class solprop.grid.EnvelopeGrid(length, reference_wavelength, t, omega, t_fine, omega_fine, dt, dt_fine, ffac, omega_collar, t_collar)[source]#
Bases:
TimeGridGrid for propagation of a complex envelope about a carrier.
The state is the full spectrum on
omega = omega0 + vwithvin FFT order, son_omega = n_tand the time samples are complex. The kernels never shift; only processing and plotting do. Build one withfrom_limits(); seeTimeGridfor the stored attributes.Examples
>>> from solprop.grid import EnvelopeGrid >>> grid = EnvelopeGrid.from_limits(1.0, 835e-9, (400e-9, 2e-6), 20e-12) >>> grid.n_omega == grid.n_t, grid.n_to == grid.n_t (True, True)
- classmethod from_limits(length, reference_wavelength, wavelength_limits, trange, *, dt=None, thg=False, ffac=None, fft_size='auto', collar_fraction=0.1, collar_placement='outside')[source]#
Build an envelope grid from the wavelength limits and the time window.
Without third harmonic the grid is sampled at twice the widest relative frequency it must carry, so the fine and coarse grids coincide and there is no oversampling unless a finer
dtis asked for. Withthg=Trueit is sampled at six times that, and the coarse grid is cropped back to the apodised window.The relative-frequency span is measured symmetrically, as the larger of
1.1 omega_max - omega0(omega_max - omega0withthg=True, where the factor 6 already leaves room for the collar) andomega0 - omega_min/2. Measuring only the upper side and applying the result to both would silently drop the whole low-frequency half of the band whenever the reference wavelength sits near the blue edge of the window.- Parameters:
- lengthfloat
Propagation distance, m.
- reference_wavelengthfloat
Reference wavelength, m; the carrier the envelope is written about.
- wavelength_limitstuple of float
Shortest and longest wavelength of the frequency window, m, strictly increasing and positive.
- trangefloat
Requested extent of the time window, s.
- dtfloat or None, optional
Requested fine sample spacing, s. The value used is this or the value the frequency window demands, whichever is smaller; a finer value here turns on oversampling.
- thgbool, optional
Leave room for third-harmonic generation. Sets the default
ffacto 6 instead of 2 and turns on oversampling.- ffacfloat or None, optional
Fine-grid oversampling factor, at least 2. Defaults to 6 with
thgand 2 without.- fft_size{‘auto’, ‘pow2’, ‘smooth’}, optional
How the transform sizes are rounded up, as for
FieldGrid.from_limits();'auto'by default.- collar_fractionfloat, optional
Width of each temporal collar as a fraction of the realised window, in
[0, 0.5), outside the requested window, as forFieldGrid.from_limits(). The default is 0.1.- collar_placement{‘outside’, ‘inside’}, optional
Where the collar lies against the request, as for
FieldGrid.from_limits();'outside'by default.
- Returns:
- EnvelopeGrid
A validated grid.
- Raises:
- GridError
If any argument is outside its valid range, or an invariant fails.
Examples
>>> from solprop.grid import EnvelopeGrid >>> grid = EnvelopeGrid.from_limits(1.0, 835e-9, (400e-9, 2e-6), 20e-12) >>> grid.n_t == grid.n_to True >>> limits = (400e-9, 2e-6) >>> thg = EnvelopeGrid.from_limits(1.0, 835e-9, limits, 20e-12, thg=True) >>> thg.n_to // thg.n_t 2
- solprop.grid.FFT_SIZES: Final = ('auto', 'pow2', 'smooth')#
The transform-size rules of
FieldGrid.from_limits()and its envelope twin.
- class solprop.grid.FieldGrid(length, reference_wavelength, t, omega, t_fine, omega_fine, dt, dt_fine, ffac, omega_collar, t_collar)[source]#
Bases:
TimeGridGrid for field-resolved propagation of a real electric field.
The state is the one-sided spectrum on
omega_k = k d_omega,k = 0 ... n_t/2, son_omega = n_t/2 + 1and the time samples are real. Build one withfrom_limits(); seeTimeGridfor the stored attributes.Examples
>>> from solprop.grid import FieldGrid >>> grid = FieldGrid.from_limits(1.5, 800e-9, (90e-9, 4e-6), 400e-15) >>> grid.n_t, grid.n_to, grid.n_omega (5120, 10240, 2561)
- classmethod from_limits(length, reference_wavelength, wavelength_limits, trange, *, dt=None, ffac=6.0, fft_size='auto', collar_fraction=0.1, collar_placement='outside')[source]#
Build a field grid from the wavelength limits and the requested time window.
The fine grid is sampled at
ffactimes the highest frequency of the window, its length is rounded up to a transform size, and the coarse grid keeps the fine bins out to just past1.1 omega_max. Note thatffacchanges the whole grid — the bin spacing, the realised window andn_omega— not only the fine one, so two values offfacgive two different grids that both satisfy the request; compare them as physical spectra on their common band, never array to array.- Parameters:
- lengthfloat
Propagation distance, m.
- reference_wavelengthfloat
Reference wavelength, m, for example the pump’s centre wavelength.
- wavelength_limitstuple of float
Shortest and longest wavelength of the frequency window, m, strictly increasing and positive.
- trangefloat
Requested extent of the time window, s. The realised window is at least this long, because the transform size is rounded up.
- dtfloat or None, optional
Requested fine sample spacing, s. The value used is this or the value the frequency window demands, whichever is smaller.
- ffacfloat, optional
Fine-grid oversampling factor, at least 2. The default 6 resolves a cubic response, whose third harmonic reaches
3 omega_max; 4 suffices for a response that generates no third harmonic, such as|E_a|^2 E. At exactly 2 the fine Nyquist frequency isomega_maxitself, so the apodisation collar above it is truncated rather than represented.- fft_size{‘auto’, ‘pow2’, ‘smooth’}, optional
How the transform sizes are rounded up:
'auto', the default, takes the cheapest even 2-3-5-smooth size between the requirement and the next power of two by a transform-cost model (fft_cost());'pow2'the next power of two;'smooth'the next even 2-3-5-smooth size.- collar_fractionfloat, optional
Width of each temporal collar as a fraction of the realised window, in
[0, 0.5). The collar lies outside the requested window: the grid is widened to at leasttrange / (1 - 2 collar_fraction)so that the whole request stays flat (SEP 21). Zero leaves no room for a temporal collar, for a run without one. The default is 0.1.- collar_placement{‘outside’, ‘inside’}, optional
'outside', the default, widens the window so that the collar lies outside the request.'inside'is the geometry before SEP 21, kept to reproduce frozen witnesses: the window is the request rounded up, and the collar takes at least collar_fraction of it, inside the request when the rounding leaves too little slack.
- Returns:
- FieldGrid
A validated grid.
- Raises:
- GridError
If any argument is outside its valid range, or an invariant fails.
Examples
>>> from solprop.grid import FieldGrid >>> grid = FieldGrid.from_limits(1.5, 800e-9, (90e-9, 4e-6), 400e-15) >>> grid.n_t, grid.n_to (5120, 10240) >>> float(grid.dt / grid.dt_fine) 2.0
- class solprop.grid.FreeGrid(radius_x, n_x, radius_y, n_y, collar_fraction=0.0)[source]#
Bases:
DisplayedConstruct a periodic Cartesian grid with x fastest in flattened columns.
- Attributes:
- radius_x, radius_yfloat
Requested physical half-widths in m, finite and positive.
- n_x, n_yint
Independent sample counts, each an integer of at least 2.
- collar_fractionfloat
Room outside each requested half-width, as a fraction of it, finite and at least 0. The periodic half-width is
radius * (1 + collar_fraction), andn_x,n_ycount every sample. The default 0 wraps at the requested half-width. Room alone absorbs nothing: a real-space collar there is requested separately (solprop.boundaries.SpatialAbsorber).- x, ynumpy.ndarray
Centred physical axes in m, shapes
(n_x,)and(n_y,). Odd sample counts place zero halfway between samples.- k_x, k_ynumpy.ndarray
Angular transverse frequencies in rad/m, in unshifted FFT order.
- rnumpy.ndarray
Distance from the origin in m, shape
(n_nodes,), x fastest.- spatial_weights, spectral_weightsnumpy.ndarray
Area and raw-DFT Parseval weights in m^2, shapes
(n_nodes,).- windownumpy.ndarray
Product of the two Planck collars, shape
(n_nodes,).- on_axisnumpy.ndarray
Complex reconstruction weights at x=y=0, shape
(n_nodes,).- kperp_sqnumpy.ndarray
Transverse wave-number squares in m^-2, shape
(n_nodes,).
- Raises:
- GridError
If dimensions, the collar, or derived floating-point arrays are invalid.
Notes
Public axes are x before y. Column
ix + n_x*iyrepresents(x[ix], y[iy]). A C-order reshape for an FFT therefore has shape(n_y, n_x). Forward transforms are unscaled; inverse transforms divide byn_x*n_y.- k_x: Float[ndarray, 'n_x']#
- k_y: Float[ndarray, 'n_y']#
- kperp_sq: Float[ndarray, 'n_nodes']#
- property n_columns: int[source]#
Return the number of flattened transverse spectral columns.
- Returns:
- int
n_x*n_y.
- on_axis: Complex[ndarray, 'n_nodes']#
- r: Float[ndarray, 'n_nodes']#
- spatial_weights: Float[ndarray, 'n_nodes']#
- spectral_weights: Float[ndarray, 'n_nodes']#
- validate()[source]#
Validate the immutable derived axes and area measures.
- Raises:
- GridError
If a derived array has invalid shape, dtype, finiteness or mutability.
- window: Float[ndarray, 'n_nodes']#
- x: Float[ndarray, 'n_x']#
- y: Float[ndarray, 'n_y']#
- class solprop.grid.GridSuggestion(wavelength_limits, trange, note)[source]#
Bases:
objectA starting point for a route’s
wavelength_limitsandtrange.- Attributes:
- wavelength_limitstuple of float
Shortest and longest wavelength, m.
- trangefloat
Length of the time window, s.
- notestr
What the suggestion assumed, and what to check.
Examples
>>> from solprop.grid import GridSuggestion >>> GridSuggestion((5e-7, 2e-6), 1e-12, "a starting point").trange 1e-12
- class solprop.grid.LineGrid(radius_x, n_x, collar_fraction=0.0)[source]#
Bases:
FreeGridConstruct a periodic line grid in x for a beam uniform in y, per metre of y.
The line is the x axis of a
FreeGrid– the same centred samples, the same unshifted FFT frequencies and the same Planck collar – with y reduced to one sample aty = 0carryingk_y = 0, no collar and a unit measure. It therefore runs as the"free"transform withn_y = 1, and every integral over the transverse plane becomes an integral over x per metre of y: energy in J/m and power in W/m, while intensity and fluence stay local, in W/m^2 and J/m^2 (transverse_measure). This is x-only free space;docs/guide/free-space/model.mdderives how its physics differs from the plane’s.- Attributes:
- radius_xfloat
Requested physical half-width in m, finite and positive.
- n_xint
Number of samples in x, an integer of at least 2.
- collar_fractionfloat
Room outside the requested half-width, as a fraction of it, finite and at least 0. The periodic half-width is
radius_x * (1 + collar_fraction); the default 0 wraps at the requested half-width.- radius_yfloat
math.inf: the field is uniform and unbounded in y.- n_yint
- x, ynumpy.ndarray
The centred x axis in m, shape
(n_x,), andy = [0.0].- k_x, k_ynumpy.ndarray
Angular frequencies in rad/m in unshifted FFT order, and
k_y = [0.0].- rnumpy.ndarray
|x|in m, shape(n_x,).- spatial_weights, spectral_weightsnumpy.ndarray
Line and raw-DFT Parseval weights in m (the spacing times one metre of y per metre of y), shapes
(n_x,).- windownumpy.ndarray
The x collar, shape
(n_x,).- on_axisnumpy.ndarray
Complex reconstruction weights at
x = 0, shape(n_x,).- kperp_sqnumpy.ndarray
k_x**2in m^-2, shape(n_x,).
- Raises:
- GridError
If the half-width, the sample count or the collar is invalid.
Notes
It is a
FreeGridso that everything that runs a Cartesian grid runs it unchanged, the backends included;FreeGriditself keeps two samples per axis. Refusals that are specific to the line, such assolprop.spatial.critical_power(), test for this class by name.Examples
>>> from solprop.grid import LineGrid >>> line = LineGrid(1e-3, 64) >>> line.n_columns, line.y.tolist(), line.transverse_measure (64, [0.0], 'per_unit_width') >>> f"{line.spatial_weights[0]:.4e} m" '3.1250e-05 m'
- property transverse_measure: Literal['per_unit_width'][source]#
Return what the grid’s transverse integrals measure.
- Returns:
- str
"per_unit_width": energies are J/m and powers W/m, per metre of y (solprop.modes.protocol.TransverseMeasure).
- class solprop.grid.RadialGrid(radius, n_r, collar_fraction=0.0)[source]#
Bases:
DisplayedConstruct an axisymmetric spatial grid, with room for a collar outside it.
- Attributes:
- radiusfloat
The requested aperture in m, finite and positive: the radius modelled flat, with no absorption.
- n_rint
Number of interior radial and spectral samples over the whole grid, the collar’s room included, at least 2.
- collar_fractionfloat
Room outside the aperture, as a fraction of radius, finite and at least 0. The Dirichlet boundary is at
radius * (1 + collar_fraction)(outer_radius). The default 0 puts it at the aperture. Room alone absorbs nothing: a real-space collar there is requested separately (solprop.boundaries.SpatialAbsorber).- hankelsolprop.hankel.QDHT
The raw transform on the outer radius, its physical scalings and integration weights.
- windownumpy.ndarray
Planck window on the radial samples, shape
(n_r,), dimensionless: one inside the aperture, falling to zero at the outer radius; it marks the region outside the request.
- Raises:
- GridError
If a dimension or the collar fraction is invalid.
Examples
>>> from solprop.grid import RadialGrid >>> grid = RadialGrid(1e-3, 64) >>> grid.r.shape, grid.k_r.shape, bool(grid.r[0] > 0) ((64,), (64,), True)
- property k_r: Float[ndarray, 'n_r'][source]#
Return the transverse spectral samples.
- Returns:
- numpy.ndarray
Positive angular frequencies in rad/m, shape
(n_r,).
- property n_columns: int[source]#
Return the number of transverse spectral columns.
- Returns:
- int
The radial sample count.
- property outer_radius: float[source]#
Return the Dirichlet boundary: the aperture with its collar’s room.
- Returns:
- float
radius * (1 + collar_fraction), m.
- property r: Float[ndarray, 'n_r'][source]#
Return the positive interior radial samples.
- Returns:
- numpy.ndarray
Radii in m, shape
(n_r,); zero and the outer boundary are excluded.
- property radial_weights: Float[ndarray, 'n_r'][source]#
Return the quadrature weights of the transverse area integral.
- Returns:
- numpy.ndarray
Weights of
2*pi*r*dr, in m^2, shape(n_r,).
- property spectral_weights: Float[ndarray, 'n_r'][source]#
Return the quadrature weights of the transverse spectral integral.
- Returns:
- numpy.ndarray
Weights of
2*pi*k_r*dk_r, in m^-2, shape(n_r,).
- validate()[source]#
Check the radial axes, weights and spatial window.
- Raises:
- GridError
If an axis is unordered or an array is mutable, nonfinite or inconsistent.
- window: Float[ndarray, 'n_r']#
- class solprop.grid.TimeGrid(length, reference_wavelength, t, omega, t_fine, omega_fine, dt, dt_fine, ffac, omega_collar, t_collar)[source]#
Bases:
DisplayedShared state of the field and envelope grids.
The eleven stored attributes below are the whole of a grid’s state; every other quantity named in
docs/dev/kernel-contract.md§2 is a property derived from them, so each has exactly one definition. Instances are frozen and hold private read-only copies of their axes, so a grid can be shared without defensive copying. Equality is by identity, because comparing whole axes elementwise is never what a caller means.Build one with
FieldGrid.from_limits()orEnvelopeGrid.from_limits()rather than by hand; the constructor is the low-level path and onlyvalidate()stands behind it.- Attributes:
- lengthfloat
Propagation distance the grid was built for, m.
- reference_wavelengthfloat
Reference wavelength, m; fixes
omega0and the co-moving frame.- tnumpy.ndarray
Coarse time axis, s, shape
(n_t,), centred on zero.- omeganumpy.ndarray
Coarse angular frequency axis, rad/s, shape
(n_omega,). Non-negative and increasing on a field grid; in FFT order aboutomega0on an envelope grid.- t_finenumpy.ndarray
Fine (oversampled) time axis, s, shape
(n_to,), centred on zero.- omega_finenumpy.ndarray
Fine angular frequency axis, rad/s, shape
(n_omega_fine,).- dtfloat
Coarse sample spacing, s.
- dt_finefloat
Fine sample spacing, s.
- ffacfloat
Oversampling factor: the fine grid is sampled at
ffactimes the highest frequency of the window. At least 2.- omega_collarCollar
Spectral collar geometry, rad/s: rises over
[omega_min/2, omega_min]and falls over[omega_max, 1.1 omega_max].- t_collarCollar
Temporal collar geometry, s, symmetric about zero and guaranteed non-degenerate.
- kind{‘field’, ‘envelope’}
Spectral layout, fixed by the subclass and passed to
solprop.fourier.
Examples
>>> from solprop.grid import FieldGrid, TimeGrid >>> isinstance(FieldGrid.from_limits(1.5, 800e-9, (90e-9, 4e-6), 400e-15), TimeGrid) True
- property active_mask: Bool[ndarray, 'n_omega'][source]#
Return the bins where the physics lives, inside the apodised window.
The dispersion relation, the noise and the error norm are evaluated here and nowhere else.
- Returns:
- numpy.ndarray
Boolean mask over the coarse frequency axis, shape
(n_omega,).
- property crop_index: ndarray[source]#
Return the positions of the coarse spectral bins inside the fine spectrum.
- Returns:
- numpy.ndarray
Index array of
numpy.intp, shape(n_omega,).
- property crop_scale: float[source]#
Return the factor applied when cropping the fine spectrum back.
- Returns:
- float
n_t / n_to.
- property d_omega: float[source]#
Return the spectral bin spacing, rad/s.
- Returns:
- float
2 pi / (n_to dt_fine), the same on the coarse and the fine grid.
- property inband_mask: Bool[ndarray, 'n_omega'][source]#
Return the bins inside the requested wavelength limits.
- Returns:
- numpy.ndarray
Boolean mask over the coarse frequency axis, shape
(n_omega,), true whereomega_min <= omega <= omega_max.
- property n_omega: int[source]#
Return the number of coarse spectral bins.
- Returns:
- int
The length of
omega.
- property n_omega_fine: int[source]#
Return the number of fine spectral bins.
- Returns:
- int
The length of
omega_fine.
- property n_to: int[source]#
Return the number of fine time samples.
- Returns:
- int
The length of
t_fine.
- omega: Float[ndarray, 'n_omega']#
- property omega0: float[source]#
Return the reference angular frequency, rad/s.
- Returns:
- float
2 pi c / reference_wavelength.
- omega_fine: Float[ndarray, 'n_omega_fine']#
- property omega_max: float[source]#
Return the highest in-band angular frequency, rad/s.
- Returns:
- float
The frequency of the shortest requested wavelength.
- property omega_max_window: float[source]#
Return the upper edge of the apodised frequency window, rad/s.
- Returns:
- float
1.1 omega_max, where the spectral collar reaches zero.
- property omega_min: float[source]#
Return the lowest in-band angular frequency, rad/s.
- Returns:
- float
The frequency of the longest requested wavelength.
- property omega_window: Float[ndarray, 'n_omega'][source]#
Return the spectral collar profile on the coarse frequency axis.
- Returns:
- numpy.ndarray
Window values in
[0, 1], shape(n_omega,), equal to 1 in band.
- property pad_scale: float[source]#
Return the factor applied when padding the coarse spectrum out.
- Returns:
- float
n_to / n_t.
- t: Float[ndarray, 'n_t']#
- t_fine: Float[ndarray, 'n_to']#
- property t_window: Float[ndarray, 'n_t'][source]#
Return the temporal collar profile on the coarse time axis.
- Returns:
- numpy.ndarray
Window values in
[0, 1], shape(n_t,), equal to 1 inside the window.
- property t_window_fine: Float[ndarray, 'n_to'][source]#
Return the temporal collar profile on the fine time axis.
Both temporal windows come from the one collar geometry, so the coarse and fine apodisations agree exactly wherever their samples coincide, rather than each window being built from its own axis’s extremes, which differ at the upper edge.
- Returns:
- numpy.ndarray
Window values in
[0, 1], shape(n_to,), 1 inside the window.
- validate()[source]#
Check every grid invariant, raising on the first that fails.
The invariants are those of
docs/dev/conventions.md§3. Bothfrom_limitsclassmethods call this, so a grid they return is always valid; call it again after building or loading one by hand.- Raises:
- GridError
If any invariant fails, naming the offending quantity.
Examples
>>> from solprop.grid import FieldGrid >>> FieldGrid.from_limits(1.5, 800e-9, (90e-9, 4e-6), 400e-15).validate()
- solprop.grid.fft_cost(n)[source]#
Return the modelled relative cost of a real transform of length n.
n log2 n, times_RADIX_PENALTYfor each factor of 3 and of 5.- Parameters:
- nint
Transform length, at least 2.
- Returns:
- float
Relative cost, comparable between lengths only.
Examples
>>> from solprop.grid import fft_cost >>> fft_cost(4096) < fft_cost(4374) # 4374 = 2 * 3^7 True
- solprop.grid.planck_taper(x, zero_low, one_low, one_high, zero_high)[source]#
Evaluate a Planck taper that rises then falls between four breakpoints.
The window is 0 at or below
zero_low, rises smoothly to 1 atone_low, stays 1 up toone_high, and falls back to 0 atzero_high. Every derivative is continuous, which is what distinguishes a Planck taper from the Tukey window thatscipy.signal.windowsprovides, and why it is written out here.- Parameters:
- xnumpy.ndarray
Points at which to evaluate the window, shape
(n,), in the same units as the breakpoints: rad/s for a spectral collar, s for a temporal one.- zero_lowfloat
Lower point at which the window reaches 0.
- one_lowfloat
Lower point at which the window reaches 1. Must exceed
zero_low.- one_highfloat
Upper point at which the window leaves 1. Must be at least
one_low.- zero_highfloat
Upper point at which the window returns to 0. Must exceed
one_high.
- Returns:
- numpy.ndarray
Window values in
[0, 1], shape(n,).
- Raises:
- GridError
If the four breakpoints are not ordered, so that a taper edge would have zero width and the window would step rather than taper.
References
D. J. A. McKechan, C. Robinson and B. S. Sathyaprakash, “A tapering window for time-domain templates and simulated signals in the detection of gravitational waves from coalescing compact binaries”, Class. Quantum Grav. 27, 084020 (2010), eq. (7).
Examples
>>> import numpy as np >>> from solprop.grid import planck_taper >>> window = planck_taper(np.array([0.0, 1.0, 2.0, 3.0, 4.0]), 0.0, 1.0, 3.0, 4.0) >>> window.tolist() [0.0, 1.0, 1.0, 1.0, 0.0]
- solprop.grid.planck_taper_derivative(x, zero_low, one_low, one_high, zero_high)[source]#
Evaluate the analytic derivative of
planck_taper()with respect tox.On an edge with outer breakpoint
aand innerb,width = b - a(negative on the falling edge),s = (x - a) / widthandr = (b - x) / width, both in(0, 1). The gate isg = 1 / (1 + exp(zeta))withzeta = 1/s - 1/r, and\[g'(x) = \frac{h(s)}{\mathrm{width}},\qquad h = \frac{1}{4\cosh^2(\zeta/2)}\left(\frac{1}{s^2}+\frac{1}{r^2}\right) > 0,\]so
g'is positive on the rising edge, negative on the falling edge, integrates to+1and-1over them, and is zero outside the tapers. The factor1/(4 cosh^2(zeta/2))is evaluated ase/(1 + e)^2withe = exp(-|zeta|), which never overflows.sandrare formed separately, so neither is obtained by cancellation. Wheremin(s, r) <= 1/740the asymptotic zero is returned and no reciprocal is formed: there the analytic value is below1e-300 / |width|. Points at or beyond the breakpoints return exactly zero. The evaluation never forms an infinite intermediate (SEP 26 section 4.2).- Parameters:
- xnumpy.ndarray
Points at which to evaluate the derivative, shape
(n,), in the units of the breakpoints.- zero_low, one_low, one_high, zero_highfloat
Breakpoints of
planck_taper(), in the same units.
- Returns:
- numpy.ndarray
dg/dxin reciprocal units ofx, shape(n,).
- Raises:
- GridError
If the breakpoints are not ordered, or an edge is so narrow that its peak derivative
2 / widthwould overflow.
See also
planck_taper_derivative_errorThe rounding bound of this evaluation.
References
D. J. A. McKechan, C. Robinson and B. S. Sathyaprakash, Class. Quantum Grav. 27, 084020 (2010), eq. (7), differentiated.
Examples
>>> import numpy as np >>> from solprop.grid import planck_taper_derivative >>> slope = planck_taper_derivative(np.array([0.5, 2.0, 3.5]), 0.0, 1.0, 3.0, 4.0) >>> slope.tolist() [2.0, 0.0, -2.0]
- solprop.grid.planck_taper_derivative_error(x, zero_low, one_low, one_high, zero_high)[source]#
Bound the absolute error of
planck_taper_derivative()at each point.The bound is
(18 + 3 |zeta|) eps |g'|where the derivative is evaluated, a first-order count of the operations of that evaluation (its comments derive it), and1e-300 / |width|in the cut-off region next to a breakpoint, where the returned zero discards at most that much. It is zero outside the tapers, where the derivative is exactly zero.- Parameters:
- xnumpy.ndarray
Points, shape
(n,), in the units of the breakpoints.- zero_low, one_low, one_high, zero_highfloat
Breakpoints of
planck_taper().
- Returns:
- numpy.ndarray
Nonnegative bound in reciprocal units of
x, shape(n,).
- Raises:
- GridError
Examples
>>> import numpy as np >>> from solprop.grid import planck_taper_derivative_error >>> bound = planck_taper_derivative_error(np.array([0.5, 2.0]), 0.0, 1.0, 3.0, 4.0) >>> bool(0.0 < bound[0] < 1e-13), float(bound[1]) (True, 0.0)
- solprop.grid.suggest(pulses, *, route='capillary')[source]#
Suggest
wavelength_limitsandtrangefor an input, as a starting point.The band is centred on the input’s carrier and spans, each side, ten times the input’s transform-limited bandwidth or a fraction of the carrier frequency, the larger: half of it on the
gnlseroute, where a supercontinuum spans about an octave, and all of it on thecapillaryroute, whose dispersive waves and ionisation blue shift reach far above the pump. The window spans thirty input durations beyond the pulses’ delays. Both are rounded outwards to two significant figures. A suggestion knows nothing of the medium or the length: it does not cover a chirp in the input’s phase, nor a dispersive wave further than it allows, nor walk-off over a long fibre. Check a run’s spectrum at the band’s edges and the boundary monitor’s verdict on the window.- Parameters:
- pulsesobject
A pulse (
GaussianPulse,SechPulse,DataPulse), a sum of them, or a sequence of them.- route{‘gnlse’, ‘capillary’}, optional
The route the grid is for.
- Returns:
- GridSuggestion
The limits, the window and what they assumed.
- Raises:
- GridError
For a route without a rule, or a pulse whose extent cannot be read.
Examples
>>> from solprop.grid import suggest >>> from solprop.pulses import GaussianPulse >>> suggestion = suggest( ... GaussianPulse(wavelength=800e-9, fwhm=7.5e-15, energy=275e-6) ... ) >>> suggestion.wavelength_limits, suggestion.trange ((3.1e-07, 4e-06), 2.3e-13)