#563 - Make the generation of correlated noise more efficient using Hermitian symmetry

Hi all,

This pull request was to make the generation of noise by the `BaseCorrelatedNoise` and derived classes more efficient, using the fact that we only desire real valued noise fields in the output.  It took me longer than I hoped to get right! (There is a script, part of this PR, in `devel/external/test_cf/` that I used as a sandbox to get this right.)

The main change then is this improvement, which happens almost exclusively within the `_generate_noise_from_rootps()` function in `galsim/correlatednoise.py`.  Since the cached variable `rootps` is now only ~half the size, this improvement also helps memory use and setup costs too.

Another, more minor change is that I no longer multiply the `rootps` values by the product of the original array shape when storing them internally within the `BaseCorrelatedNoise`.  This is necessary to do somewhere because of the asymmetry in the the `numpy.fft` convention for the DFT, and the fact that the power spectrum (PS) has the units of the square of a DFT of a noise field.  I opted to move this accounting into the `_generate_noise_from_rootps` function, simplifying `_get_update_rootps()` and `_get_update_rootps_whitening()` slightly, while on the downsise adding an additional instruction (do divide by an array dimension product) to the `CorrelatedNoise.__init__()` method.  It was a marginal call, but from working with the code this way of doing things seemed more natural, and less hidden.

I don't have a great deal to add to the discussion on #563 .  The current state of the noise realization generation code is described in the following comment: https://github.com/GalSim-developers/GalSim/issues/563#issuecomment-48053798 .
Why yes I can explain, and in fact I thought I did...

>Another, more minor change is that I no longer multiply the rootps values by the product of the original array shape when storing them internally within the BaseCorrelatedNoise. This is necessary to do somewhere because of the asymmetry in the the numpy.fft convention for the DFT, and the fact that the power spectrum (PS) has the units of the square of a DFT of a noise field. I opted to move this accounting into the `_generate_noise_from_rootps` function, simplifying `_get_update_rootps()` and `_get_update_rootps_whitening()` slightly, while on the downsise adding an additional instruction (to divide by an array dimension product) to the `CorrelatedNoise.__init__()` method. It was a marginal call, but from working with the code this way of doing things seemed more natural, and less hidden.

And the other point in the code that you identify, where we multiply the product, is precisely the point in `_generate_noise_from_rootps()` where I try to bring this all into one place.  Except that this is not totally possible, since the `CorrelatedNoise.__init__()` needs to know about the units too.

As I said, it was a marginal call, and I am not tied to it.  But I felt it was better not to have the old convention need to be put in by hand in each of `_get_update_rootps` and `_get_update_rootps_whitening` and whatever other similar functions we might put in place in future for another function of the correlated noise. (Indeed, in the immediate future, for @rmandelb 's work-in-progress on #567 / #529 , we potentially have to worry about it when generating the symmetrized PS...)

The problem with the one sided 1/N in this FFT convention is that it screws things up as soon as you need to start squaring (or square-rooting) the results of DFTs!