Hello everyone! It has been a while since my last blog, and for a good reason. The past few weeks have been quite productive, and I thought it might be a good idea to present one final report of the work that I did over this past month instead of breaking it into subparts. With this blog, I will also be marking the end of my journey through the Google Summer of Code program. This blog will talk about some of the changes that the work I did as a part of GSoC brought to RADIS, and how you, the user can and will benefit from it.
In my last blog, I briefly mentioned what I was planning to do with the GPU code and how to integrate it with RADIS. The current RADIS code performs calculation of spectra at thermal equilibrium (and even in non-equilibrium conditions) in primarily two ways:
- by defining a
SpectrumFactoryobject, and then calling the method
- by passing the necessary parameters in the method
calc_spectrum, which returns a Spectrum object directly
In our attempt to add support for GPU accelerated spectrum calculation, we wanted to keep the interface as similar to the original one as possible. Thus, the new method which we introduced to calculate the spectrum using GPU was naturally called
calc_spectrum method, which is actually a wrapper that makes of the
eq_spectrum method underneath, was also modified and a new parameter called
mode was added. Depending on what the value of
mode is, the calculation of spectrum could be performed either on the GPU or on the CPU.
Now coming to the implementation of
eq_spectrum_gpu, I tried to keep the structure of the code as similar to the current CPU implementation as possible. What it meant was that the preprocessing done was in a way quite similar to the CPU version of the method. The difference actually came in during the broadening step. Initially our implementation was different from the CPU version when it came to loading the data, primarily because the data being loaded in the GPU method was in the ‘npy’ format. This made it necessary to implement another method for loading this data, as the data loader in RADIS did not support npy files. While implementing this was not difficult, it was not seen as a very good design decision, as this type of loading and handling of data was very isolated and not compatible with the rest of RADIS’ features. Therefore, ultimately it was to keep this mpy2df method as an additional, helper method, and instead of using it as the primary source of data, we use the dataframe which RADIS already generates instead. This allowed us to keep things compatible with the current implementation to a great extent, and the only downside, if it can be considered that, was the need to now compute the parameters before the spectrum is calculated, which in case of npy files were already present for us. This however, was virtually a non-problem since this step was not even remotely close to the bottleneck, and the flexiblity it provided in terms of loading and preprocessing data outweighed this extra computation easily. At this point we had the data loaded in memory, either through the legacy data loader using the dataframe, or by passing the location of the npy files in the system and loading them directly. After this, we had to pass this data to the GPU module. The GPU module, titled py_cuFFS, is actually a Cython file with some CuPy, which serves as the complete host+device code for the computation of the spectra. Using Cython over Python allows us to compile the module prior to using it, which gives an added performance boost. The compilation however, is a machine-specific process and cannot have a single-file-handles-all kind of implementation. Thus, instead of sharing the binary file with the users, we instead share the source code. Whenever the user calls the GPU accelerated methods on their system for the first time, RADIS automatically compiles the source code into the binary, which then gets compiled according to the system environment of the user. Now, the compiled binary is imported by RADIS, and the input parameters such as the temperature, pressure and the partition function are passed on to the GPU.
The GPU module returns the spectrum to RADIS, which then computes other quantities, such as the absorbance and transmittance from this. From this stage onwards the code for
eq_spectrum_gpu is identical. Both the methods update the metainformation such as the calculation time, number of lines calculated, etc. In order to read more about the GPU module and how to use it, I highly recommend the users to go through the documentation which has not just examples but also a guide on how to setup your system in order to make use of these GPU accelerated methods. If you’d just like to observe for now, I would recommend going through this notebook on radis-benchmark which gives an example of how to use these methods to calculate the spectrum on the GPU, and an impressive speed test between the GPU and the CPU methods when calculating spectra with 5M lines.
This wraps up my journey with RADIS a Google Summer of Code participant. It has been an excellent experience with a great deal of learning involved. I had prior experience of working with CUDA for deep learning pipelines but this was a completely new domain. In addition to the programming itself, I got exposed to the world of spectroscopy which was also very interesting. While my contribution to RADIS under the GSoC aegis comes to an end with this blog, I am still really excited to be a part of RADIS as it grows further. My GSoC project started what would hopefully end with a completely GPU-accelerated RADIS, but there is still plenty of work before we can say that. My GSoC project implemented the thermal equilibrium variant of the spectrum calculation method, but we still need to work on non-equilibrium methods. In addition, we also need to modify the GPU code itself to allow support for weighted air- and self-collision factors, among other things. There’s a lot to do, but I think we’ve had a good start. Most importantly, I am happy with the way I am ending this project. The code is ready and we have proper guide, documentation and examples in place so any new user can easily try this feature out themselves! I am really excited about the feedback and what users have to say about this GPU implementation. Finally, none of this would have been possible without the constant support and assistance from my amazing mentors, Erwan ( @erwanp ) and Dirk ( @dcmvdbekerom ). It would be hard to understate the contribution they’ve made to my project, helping constantly not just with the code but also in designing and planning the next steps. My lack of knowledge in the domain of spectroscopy was a huge pain at times which led to extremely long periods of slow progress due to painful debugging, but they always took out time from their packed schedules to help me out. Once again, thank you! It has been a wonderful experience, working with RADIS and I am really excited to see what how RADIS grows in the future!
P.S. for anyone who’d like to go through the code of the project, you can find the pull request here: https://github.com/radis/radis/pull/117. And more importantly, if you’d like to know more, want to contribute, or just talk to the team, feel free to join us at our slack here.