Addition of CuPy as an Accelerated Computing Option #1
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This is a copy of PR spacetelescope#499 to the spacetelescope/poppy repository.
This is a bit more of an extensive PR as it seeks to add CuPy as an accelerated math option for many computations including FFTs, MFTs, and exponentials for propagation with the OpticalSystem or FresnelOpticalSystem classes. To start with, CuPy is a package for GPU accelerated computing. While POPPY has GPU computing options available with PyOpenCL and with pyculib (which has been deprecated by Numba in favor of CuPy), this implementation seeks to perform all calculations on the GPU until the end of propagation. This reduces time for calculations as arrays no longer need to be transferred between GPU memory and standard memory when performing different calculations.
CuPy has been designed to be very similar to Numpy and has many of the same features requiring the same syntax to use. An example is numpy.fft.fft2, which with CuPy is cupy.fft.fft2. The catch is that CuPy functions can not be used on Numpy arrays since Numpy arrays are stored on standard memory. As such, the implementation strategy was to use the statement “import cupy as np” when POPPY’s Config has been set to use CuPy. This makes performing all calculations on GPU more seamless as wavefront arrays for Wavefront or FresnelWavefront objects along with optical element phasors are automatically calculated as CuPy arrays.
In addition to using CuPy for basic computations of FFTs and exponentials, CuPy also enables the use of many SciPy functions through its cupyx functions. The cupyx functions can be imported much like many scipy functions with a statement such as “import cupyx.scipy.ndimage as ndimage”. So many functions for computing array rotations or interpolations are also imported through cupyx or scipy based on POPPY’s Config setup. The same method is also used to compute Bessel functions.
Currently, many optics have been tested for use with CuPy. A table with these optics is provided below with some comments regarding the functionality of some optics.
All tests in the test suite for POPPY were also run. Currently, there is only an issue with the KolmogorovWFE test not passing due to a units issue in an exponential. This only comes up when using a Tatarski power spectrum. The tests have only been run with standard CPU computations to make sure POPPY is not running into critical errors because of the addition of CuPy even if a user isn’t using the CuPy feature.
Computation comparisons have been performed to illustrate the benefit of this accelerated computing feature. Below are comparisons of the times required for a PSF to be calculated for varying array sizes using the MKL FFT option versus the CuPy calculations. The optical systems tested had 5 different surfaces/optics. The system used for these comparisons was the University of Arizona’s HPC Puma nodes. The node utilized 32 AMD EPYC 7642 CPUs and the NVIDIA Tesla V100S GPU.
One catch with this is none of POPPY’s display functionality is compatible with CuPy. This is because matplotlib cannot plot CuPy arrays since they are only on GPU memory. In order to obtain a Numpy array from a CuPy array, the “cupy.ndarray.get()” method can be used. So users can obtain intensity and phase arrays by adding .get().
It should be noted that the following POPPY features have not been tested for functionality with CuPy: