#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 .
> Like the tests of shear applied to whitened RealGalaxy images that @msimet conducted last summer in the work 
> that ended up in S9 of the GalSim paper.

That's a big undertaking.  But I guess some people who have other applications might rely on the fact that the requirements for shear are quite stringent.  (Just to clarify things, my confusion had come from been that I had taken "application" to mean "application of some new correlation noise object to an image" rather than "application for which they want to make images with GalSim"... as in the comment was suggesting that even for shear this might have to be retested when applying some new noise CF.  That was kind of a scary thought.)

> Something like if np.sum(np.abs(ps.imag)) >= np.sum(np.abs(ps.real)): warnings.warn("BLAH")?

Yes, but inserting a ```0.01*``` on the RHS - I assume we want to warn if the imaginary part is more than a % or so of the real part, don't we?

> By the way, your comment has made me realise a much more serious error in that comment, being that the 
> problem here is not that the PS is not totally real, but that it might not necessarily all be positive because the CF 
> that we have DFTed above is only approximate. So what would be needed here is a test of the sum of the 
> absolute values of the negative elements relative to the sum of the absolute values of the positive elements, say...

Good point.  yes, I think that's a very good idea.