New Features
* Surface/Wavefront error synthesis: `prysm.interferogram` now contains the `synthesize_surface_from_psd` core method and `render_synthetic_surface` and `Interferogram.render_from_psd` convenience wrappers for synthesizing surface or wavefront data from PSD curves. Examples of this technique can be seen in e.g. _E. Sidick Power Spectral Density Specification and Analysis of Large Optical Surfaces_.
* convenience wrapper `Interferogram.fit_zernikes` replacing `zernikefit(i.phase, ...)` invocation.
* `write_zygo_ascii` function in `prysm.io` to write Zygo ASCII files.
* `Interferogram.save_zygo_ascii` to write an interferogram to Zygo ASCII format.
* `zorder` parameter in line-based plotting functions -- `OpticalPhase.plot_slice_xy`, `Convolvable.plot_slice_xy`, `Interferogram.plot_psd_xy_avg`
* `mode` argument on `Interferogram.plot_psd_xy_avg` to switch between x axis units of spatial frequency (`mode='freq'`) or spatial period (`mode='period'`).
* `Interferogram.psd_slices` and `Interferogram.plot_psd_slices` methods replacing `psd_xy_avg` method. Two new inquiries are `azmin` and `azmax` for the azimuthal minimum and azimuthal maximum.
* `PSF.polychromatic` staticmethod to create polychromatic PSFs from ensembles of monochromatic ones. This essentially reintroduces the `MultispectralPSF` class's functionality from earlier versions of prysm.
* more configuration options. `prysm.config` now has parameters for `Q`, `phase_colormap`, `image_colormap`, `lw`, `zorder` for controlling the default values of these parameters throughout the library.
* new constants in `prysm.psf` -- `FIRST_AIRY_ZERO`, `SECOND_AIRY_ZERO`, AND `THIRD_AIRY_ZERO` as well as `SECOND_AIRY_ENCIRCLED` AND `THIRD_AIRY_ENCIRCLED`. These concern the zeros of the airy disk and how much of the total energy is contained within. They are all wrapped in `AIRYDATA`, a dictionary with keys of 1,2,3 and values that are length-2 tuples of (radius, encircled energy).
Beta features
* `prysm.otf.long_exposure_otf` and `prysm.otf.estimate_Cn` for calculating the OTF (MTF) associated with a 'long' exposure through atmospheric turbulence. Note that while the equations have been implemented, the results have not been checked against published values. Please provide feedback.
Improved packaging
* prysm now uses `setup.cfg` and some setuptools tricks. It now has the `prysm.__version__` attribute and can be more easily scanned by crawlers without executing setup.py.
Improved documentation
* The User's guide and Examples sections of the documentation are now jupyter notebooks and have embedded graphics and output.
* There are several new examples.
Improved test coverage
* Test coverage is now > 80%
breaking API changes
* `Interferogram.psd_xy_avg` has been removed, its functionality is now the same as the default for` Interferogram.psd_slices`
* `Interferogram.plot_psd_xy_avg` faces the same change for `Interferogram.plot_psd_slices`. Note that two calls are now needed to replicate the default behavior:
python
fig, ax = i.plot_psd_slices(x=True, y=True, alpha=0.4, lw=3)
fig, ax = i.plot_psd_slices(x=False, y=False, azavg=True, lw=4.5, fig=fig, ax=ax)
* `prysm.psf._airydisk` has been renamed to `prysm.psf.airydisk`.
* the `lens` submodule has been removed. This eliminates the `Lens` class.
* the `seidel` submodule has been removed. This eliminates the `Seidel` class.
* the `shackhartmann` submodule has been removed. This eliminates the `Shackhartmann` class.
* the `macros` submodule has been removed. This eliminates the `SystemConfig` namedtuple, the `thrufocus_mtf_from_wavefront` and `thrufocus_mtf_from_wavefront_array` functions.
* `prysm.detector.generate_mtf` has been removed. This function is redundant with `prysm.detector.pixelaperture_analytic_otf`.
* `prysm.detector.OLPF.__init__` now defaults to `samples_x=0`, using the analytical representation in the numerical case.
* The great Zernike refactor of 2019:
* * `prysm.fringezernike` has been folded into `prysm.zernike`. Several functions have been renamed:
* * * `fit` is now `zernikefit` called as `zernikefit(... map_='fringe')` (or `map_='noll')
* * * magnitude/angle and name functions are now part of the `zernikefuncs` dictionary of dictionaries. Keys are, in order, function type and zernike order. `fzname` is now accessed most easily as `zernikefuncs['name']['fringe']`. `fzset_to_magnitude_angle` as `zernikefuncs['magnitude_angle']['fringe']. `noll` is a valid key for the nested dictionary.
* * * `FZCache` and `fzcache` are nwo made redundant by `ZCache` and `zcache`. The cache takes an index into the `prysm.zernikes.zernikes` list, not a Fringe or Noll index. Use `prysm.zernikes.maps` to convert Fringe or Noll indices into prysm's zernike catalog.
* * the `StandardZernike` class from `prysm.standardzernike` has been replaced with `NollZernike` from `prysm.zernike,` or as imported from the top-level namespace.
* * * `NollZernike` allows coefficients from 0 to 36 or 1 to 37 and has all features present in `FringeZernike`, unlike the prior `StandardZernike` class.
* * `prysm._zernike` is now `prysm.zernike`
under-the-hood changes
* Angles of rotationally invariant terms in Fringe Zernike magnitude sets are now zero.
* use of `isfinite` and `isnan` optimized for internal routines.
bugfixes
* `wavelength` is properly captured in `Pupil.from_interferogram.`
* `Convolvable.from_file` no longer mangles x and y units.
* `PSF.encircled_energy` has been reworked, improving accuracy by about 2.3%.
* `BasicData.center_x` and `center_y` are now properly computed. Fixes 2 .