prysm v0.20#
Summary#
Version 20 of prysm is the largest breaking release the library has ever had. Your programs will be more a bit verbose when written in this style, but they will be more clear, contain fewer bugs, and run faster. This version marks prysm transitioning from an extremely object oriented style to a data oriented style. The result is that code is more direct, and there is less of it. Side benefits are that by deferring the caches that used to help keep prysm fast to the user level, the user is in control over their program’s memory usage. A new high level object oriented API may be produced at some point, likely in a separate package.
This version will produce one more zero point release (0.21) for cleanup after longer experience in this style, after which version 1 will be released. In addition to the breaking changes, this release brings landmark additions:
2D-Q polynomials also known as Forbes polynomials, Chebyshev, Legendre, and Hopkins polynomials,
Sophistocated, highly optimized tools for segmented apertures.
Tilted plane projections for DMs and other oblique elements
Realistic detector noise modeling
Bayer focal plane routines
As perhaps a motivational comment, the official model of the Low Order Wavefront Sensing and Control (LOWFS/C) system on the Roman Coronagraph Instrument was ported from prysm v0.19 to v0.20, and runs 12x faster on CPU and 6x faster on GPU. A total of two new lines of code were gained in aggregate. The port took approximately two person-hours. The model now runs in 430 microseconds per wavelength through the 7-plane model; over twice faster than the actual realtime WFSC system!
The remainder of this page will be divided by logical unit of function, then sub-divided between breaking changes and new features.
Changes#
Contents
bayer#
This is a new submodule, for working with bayer imaging systems. It provides a complete toolkit for both forward modeling and processing of bayer images, real or synthetic. The following functions are included:
wb_prescale()for performing white-balance pre-scaling to mosaiced data in-place.wb_scale()for performing white-balance scaling to RGB data in-place.composite_bayer()for compositing dense color plane data into a bayer mosaic. This function is used to synthesize “raw” bayer imagery in a forward model.decomposite_bayer()for “sifting” bayer subplanes from a mosaiced image.recomposite_bayer()the inverse operation of decomposite_bayer, for taking bayer subplanes and re-mosaicing them.composite_bayerworks with fully dense data with (m, n) pixels per color plane.recomposite_bayerworks with sparse data with (m/2, n/2) pixels per color plane.demosaic_malvar()for performing Malvar-He-Cutler demosaicing.
conf#
All
Labelsrelated code has been removed. There is no substitute.Unit munging has been removed; wavelengths are no longer astropy units but are floats with units of microns again.
The following parameters have been removed from
Config:Q
wavelength
interpolation
unit_format
show_units
phase_xy_unit
phase_z_unit
image_xy_unit
image_z_unit
mtf_xy_unit
mtf_z_unit
ptf_xy_unit
ptf_z_unit
pupil_labels
interferogram_labels
convolvable_labels
mtf_labels
ptf_labels
psd_labels
convolution#
This module has been substantially rewritten. Up to version 0.19, a Convolvable object was the key to the convolution API, which was capable of forming prototypical FFT based convolution, as well as convolution with various analytic blurs, and convolution of datasets which were not equally sampled. The API has been significantly simplified and disentangled in this version.
Breaking:
Convolvableno longer exists.the
deconvmethod for Wiener-Helstrom deconvolution no longer exists
The new API is comprised of:
conv(), for convolving an object with a PSF.apply_transfer_functions(), for blurring an object with N transfer functions.
coordinates#
GridCacheand its variable transformation functions have been deleted. The functionality is deferred to the user, who can quite naturally write code that reuses grids.make_xy_grid()has had its signature changed from(samples_x, samples_y, radius=1)to(shape, *, dx, diameter, grid=True). shape auto-broadcasts to 2D and dx/diameter are keyword only. grid controls returning vectors or a meshgrid.make_xy_gridis now FFT-aligned (always containing a zero sample).make_rho_phi_grid()has been removed, combinemake_xy_grid()withcart_to_polar().New warping function suite used to work with non-normal incidence beams (e.g., DMs, OAPs)
degredations#
The
Smearclass has been removed, and replaced withsmear_ft()The
Jitterclass has been removed, and replaced withjitter_ft()
detector#
The
Detectorclass has been reworked, and its purpose changed. Previously, it existed to impart blur into a system as would be experienced given a particular pixel design. It now exists to model noise. Expect no API compatibility between v0.19 and v0.20.The
OLPFclass has been removed, and replaced witholpf_ft()The
PixelApertureclass has been removed, and replaced withpixel_ft()bindown_with_units()was removed.bindown()will now error if the array dimensions are not an integer multiple of the binning factor. It now supports ND data, with possible unique factors per dimension.tile()has been added, which is the adjoint operation to bindown. It replicates the elements of an arrayfactortimes, and has the same ND support bindown now does.
fttools#
The matrix DFT executor was mildly reworked. There is no more
normoption. The code was modified such that a forward-reverse calculation that goes to any domain containing the majority of the spectrum of the signal and returns to the same input domain will be energy conserving automatically. This means thatidft2(dft2(x)) ~= x
geometry#
The geometry module was rewritten. The object oriented mask interface and MaskCache have been removed. All functions now take x, y or r, t args as appropriate, instead of samples. The arguments now all have consistent units.
Higher side count regular polygon functions have been removed, use
regular_polygon()directly:heptagon()
octagon()
nonagon()
decagon()
hendecagon()
dodecagon()
trisdecagon()
inverted_circle()was removed, call~circle(...)for equivalent output.
io#
write_zygo_ascii()no longer takes ahigh_phase_resparameter. It did not do anything before and has been removed, as it is not likely prysm needs to support ancient version of MetroPro that are incompatible with that convention.the dat and datx readers no longer flip the phase and intensity data upside down. They used to do this due to prysm explicitly having an origin in lower left convention, but v0.20 has no enforced convention for array orientation, and the flipud is an unexpected behavior in this paradigm.
mathops#
The several quasi-identical classes to shim over numpy and scipy were removed and replaced with a single BackendShim type. The engine variable no longer exists. Users should overwrite prysm.backend.np._srcmodule, as well as the same for fft, ndimage, etc.
interferogram#
The interferogram module is largely unchanged. With the removal of astropy units, the user must manage their own units. Phase is loaded from dat/datx files in units of nm.
prysm.interferogram.Interferogram.fit_zernikes()was removed, use lstsq from the polynomials submodule withInterferogram.data, Interferogram.x, Interferogram.y, Interferogram.r, Interferogram.tdirectly, minding spatial axis normalization.prysm.interferogram.Interferogram.remove_piston_tiptilt_power()andprysm.interferogram.Interferogram.remove_piston_tiptilt()have been removed, callremove_piston(), etc, in sequence.prysm.interferogram.Interferogram.mask()now accepts arrays only.filter()has returned to stay and uses a new 2D filter design method behind the scenes. The out-of-band rejection is approximately 50dB higher for typical sized arrays.
jacobi#
See the new polynomials module.
objects#
The changes to this module are similar to geometry. Functions no longer take a samples argument, but take x/y or r,t grids directly. Objects which have analytic fourier transforms retain functions to compute those.
Pinholehas been removed, usepinhole()andpinhole_ft()SiemensStarhas been removed, usesiemensstar()TiltedSquarehas been removed, usetiltedsquare()SlantedEdgehas been removed, useslantededge()Chirpwas removed without replacementGratingwas removed without replacementGratingArraywas removed without replacement
otf#
The OTF module was maed data oriented instead of object oriented, in line with the rest of the changes to prysm in this release. Note that the three functions below accept both arrays, and RichData-like objects with data and dx attributes, and return RichData objects.
MTFwas removed, usemtf_from_psf()PTFwas removed, useptf_from_psf()OTFwas removed, useotf_from_psf()
polynomials#
prysm’s support of polynomials has been unified under a single package. The polynomials package is now the fastest known for the supported polynomials, e.g. beating POPPY by more than a factor of 100 on large collections of Zernike polynomials. This speed introduces mild complexity into the API, which must be appreciated. For a complete tutorial see Ins and Outs of Polynomials.
prysm.polynomials/- top level routines, common to any basis set:lstsq()for least-squares fitting of 2D basis functions to data
sum_of_2d_modes()for (weighted) summing 2D modes. This function does whatzernike_composeorzernike_sumdoes in other packages, once the user has the basis set in hand.
sum_of_xy_modes()some polynomial bases, like the Legendre and Chebyshev polynomials, are separable in the x, y dimensions. This function reflects that, and reduces the time complexity from (m*n) per mode to (m+n) per mode. This can bring, for example, a 1000x speedup for 1024x1024 arrays.mode_1d_to_2d()for broadcasting a separable 1D mode to a 2D array
separable_2d_sequence()for computing a set of separable polynomials, such as the Legendre or Chebyshev polynomials, in 2D, with optimal time complexity.
/zernikefor Zernike polynomials. These functions are all re-exported at the root ofpolynomials/:
Stand-alone functions for the first few terms have been removed, use zernike_nm with one of the naming convention functions to replace the behavior:
piston()
tip()
tilt()
defocus()
primary_astigmatism_00()
primary_astigmatism_45()
primary_coma_y()
primary_coma_x()
primary_spherical()
primary_trefoil_x()
primary_trefoil_y()
e.g.,
for primary_coma_y, eitherzernike_nm(3, 1, ...)orzernike_nm(*zernike_noll_to_nm(7), ...)
classes
FringeZernike,NollZernike,ANSI1TermZernike,ANSI2TermZernikehave been removed. Combinezernike_nm()with one of the naming functions to replace the phase synthesis behavior.
zernike_norm()for computing the norm of a given Zernike polynomial, given the ANSI order (n, m).
zero_separation()for computing the minimum zero separation on the domain [0,1] for a Zernike polynomial, given the ANSI order (n, m).
zernike_nm()for computing a Zernike polynomial, given the ANSI order (n, m).
zernike_nm_sequence()– use to compute a series of Zernike polynomials. Much faster thanzernike_nm()in a loop. Returns a generator, which you may want to exhaust into a list or into a list, then an array.
nm_to_fringe()for converting ANSI (n, m) indices to FRINGE indices, which begin with Z1 for piston.
nm_to_ansi_j()for converting ANSI (n, m) indices to ANSI j indices (dual to mono index).
noll_to_nm()for converting the Noll indexing scheme to ANSI (n, m).
fringe_to_nm()for converting the FRINGE indexing scheme to ANSI (n, m).
zernikes_to_magnitude_angle_nmkey()for converting a sequence of[(n1, m1, coef1), ...]to a dictionary keyed by(n, |m|)with the magnitude and angle as the value. This basically converts the “Cartesian” Zernike polynomials to a polar representation.
zernikes_to_magnitude_angle()for doing the same aszernike_to_magnitude_angle_nmkey, but with dict keys of the form “Primary Coma” and so on.
nm_to_name()for converting ANSI (n, m) indices to a friendly name like “Primary Trefoil”.
top_n()for identifying the largest N coefficients in a Zernike series.
barplot()for making a barplot of Zernike polynomials, based on their mono index (Z1..Zn)
barplot_magnitudes()for doing the same asbarplot, but with labels of “Tilt”, “Power”, and so on.
/chebyfor Chebyshev polynomials. These functions are all re-exported at the root ofpolynomials/:
cheby1(), the Chebyshev polynomial of the first kind of order n
cheby2(), the Chebyshev polynomial of the second kind of order n
cheby1_sequence(), a sequence of Chebyshev polynomials of the first kind of orders ns; much faster thancheby1in a loop.
cheby2_sequence(), a sequence of Chebyshev polynomials of the second kind of orders ns; much faster thancheby2in a loop.
/legendrefor Legendre polynomials. These functions are all re-exported at the root ofpolynomials/:
legendre(), the Legendre polynomial of order n
legendre_sequence(), a sequence of Legendre polynomials of orders ns; much faster thanlegendrein a loop.
/jacobifor Jacobi polynomials. These functions are all re-exported at the root ofpolynomials/:
jacobi(), the Jacobi polynomial of order n with weight parameters alpha and beta
jacobi_sequence(), a sequence of Jacobi polynomials of orders ns with weight parameters alpha and beta; much faster thanjacobiin a loop.
/qpolyfor Q (Forbes) polynomials. These functions are all re-exported at the root ofpolynomials/:
Qbfs(), the Q best fit sphere polynomial of order n, at normalized radius x.
Qbfs_sequence(), the Q best fit sphere polynomials of orders ns, at normalized radius x. Much faster thanQbfsin a loop.
Qcon(), the Q best fit sphere polynomial of order n, at normalized radius x.
Qcon_sequence(), the Q conic polynomials of orders ns, at normalized radius x. Much faster thanQconin a loop.
Q2d(), the 2D-Q polynomials of order (n, m). Note that the API is made the same as Zernike by intent, so the sign of m controls whether it is a cosine (+) or sine (-), not a and b coefficients.
Q2d_sequence(), the 2D-Q polynomials of orders [(n1, m1), …]. Much faster thanQ2din a loop.
propagation#
prop_pupil_plane_to_psf_plane()andprop_pupil_plane_to_psf_plane_units()have been removed, they were deprecated and marked for removal.Any argument which was
sample_spacingis nowdx.Any
coherentargument was removed, all routines now explicitly work with fields (seeprysm.propagation.Wavefront.intensity()).Any
normargument was removed.Units are no longer fed through astropy units, but are mm for pupil plane dimensions, um for image plane dimensions, and nm for OPD.
Angular spectrum (free space) propagation now allows the transfer function to be computed once and passed as the
tfkwarg, accelerating repetitive calculations.See also:
~prysm.propagation.angular_spectrum_transfer_function
The
focus_unitsandunfocus_unitsfunctions were removed. Since prysm largely bookkeepsdxnow, they are superfluous.
psf#
The PSF module has changed from being a core part of propagation usage to a module purely for computing criteria of PSFs, such as fwhm, centroid, etc.
PSFhas been removedall metrics and measurements have moved from being methods of PSF to top-level functions:
the Airy Disk can be synthesized with
airydisk(), or its transfer function withairydisk_ft()
pupil#
this entire submodule has been removed. To synthesize pupil functions which have given phase and amplitude, combine prysm.geometry with prysm.polynomials or other phase synthesis code. The function
from_amp_and_phase()largely replicates the behavior of thePupilconstructor, with the user generating their own phase and amplitude arrays.
segmented#
This is a new module for working with segmented systems. It contains routines for rasterizing segmented apertures and for working with per-segment phase errors. prysm’s segmented module is considerably faster than anything else in open source, and is approximately constant time in the number of segments. For the TMT aperture, it is more than 100x faster to rasterize the amplitude than POPPY. For more information, see This post. The Notable Telescope Apertures page also contains example usage.
rasterizes the pupil upon initialization and prepares local coordinate systems for each segment.
A future update will bring fast per-segment phase errors with a clean API.
qpoly#
See the new polynomials module.
util#
This module is likely to move to prysm.stats in a future release.
is_odd()andis_power_of_2()have been moved to the mathops module.
wavelengths#
This data-only module has been changed to contain all quantities in units of microns, now that prysm no longer uses astropy.
zernike#
See the new polynomials module.