def main(): pr = cProfile.Profile() pr.enable() rng = galsim.UniformDeviate(8675309) wcs = galsim.FitsWCS('../tests/des_data/DECam_00154912_12_header.fits') image = galsim.Image(xsize, ysize, wcs=wcs) bandpass = galsim.Bandpass('LSST_r.dat', wave_type='nm').thin(0.1) base_wavelength = bandpass.effective_wavelength angles = galsim.FRatioAngles(fratio, obscuration, rng) sensor = galsim.SiliconSensor(rng=rng, nrecalc=nrecalc) # Figure out the local_sidereal time from the observation location and time. lsst_lat = '-30:14:23.76' lsst_long = '-70:44:34.67' obs_time = '2012-11-24 03:37:25.023964' # From the header of the wcs file obs = astropy.time.Time(obs_time, scale='utc', location=(lsst_long + 'd', lsst_lat + 'd')) local_sidereal_time = obs.sidereal_time('apparent').value # Convert the ones we need below to galsim Angles. local_sidereal_time *= galsim.hours lsst_lat = galsim.Angle.from_dms(lsst_lat) times = [] mem = [] phot = [] t0 = time.clock() for iobj in range(nobjects): sys.stderr.write('.') psf = make_psf(rng) gal = make_gal(rng) obj = galsim.Convolve(psf, gal) sed = get_sed(rng) waves = galsim.WavelengthSampler(sed=sed, bandpass=bandpass, rng=rng) image_pos = get_pos(rng) sky_coord = wcs.toWorld(image_pos) bounds, offset = calculate_bounds(obj, image_pos, image) ha = local_sidereal_time - sky_coord.ra dcr = galsim.PhotonDCR(base_wavelength=base_wavelength, obj_coord=sky_coord, HA=ha, latitude=lsst_lat) surface_ops = (waves, angles, dcr) obj.drawImage(method='phot', image=image[bounds], offset=offset, rng=rng, sensor=sensor, surface_ops=surface_ops) times.append(time.clock() - t0) mem.append(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) phot.append(obj.flux) image.write('phot.fits') phot = np.cumsum(phot) make_plots(times, mem, phot) pr.disable() ps = pstats.Stats(pr).sort_stats('time') ps.print_stats(20)
def test_dcr(): """Test the dcr surface op """ # This tests that implementing DCR with the surface op is equivalent to using # ChromaticAtmosphere. # We use fairly extreme choices for the parameters to make the comparison easier, so # we can still get good discrimination of any errors with only 10^6 photons. zenith_angle = 45 * galsim.degrees # Larger angle has larger DCR. parallactic_angle = 129 * galsim.degrees # Something random, not near 0 or 180 pixel_scale = 0.03 # Small pixel scale means shifts are many pixels, rather than a fraction. alpha = -1.2 # The normal alpha is -0.2, so this is exaggerates the effect. bandpass = galsim.Bandpass('LSST_r.dat', 'nm') base_wavelength = bandpass.effective_wavelength base_wavelength += 500 # This exaggerates the effects fairly substantially. sed = galsim.SED('CWW_E_ext.sed', wave_type='ang', flux_type='flambda') flux = 1.e6 base_PSF = galsim.Kolmogorov(fwhm=0.3) # Use ChromaticAtmosphere im1 = galsim.ImageD(50, 50, scale=pixel_scale) star = galsim.DeltaFunction() * sed star = star.withFlux(flux, bandpass=bandpass) chrom_PSF = galsim.ChromaticAtmosphere(base_PSF, base_wavelength=base_wavelength, zenith_angle=zenith_angle, parallactic_angle=parallactic_angle, alpha=alpha) chrom = galsim.Convolve(star, chrom_PSF) chrom.drawImage(bandpass, image=im1) # Use PhotonDCR im2 = galsim.ImageD(50, 50, scale=pixel_scale) dcr = galsim.PhotonDCR(base_wavelength=base_wavelength, zenith_angle=zenith_angle, parallactic_angle=parallactic_angle, alpha=alpha) achrom = base_PSF.withFlux(flux) rng = galsim.BaseDeviate(31415) wave_sampler = galsim.WavelengthSampler(sed, bandpass, rng) surface_ops = [wave_sampler, dcr] achrom.drawImage(image=im2, method='phot', rng=rng, surface_ops=surface_ops) im1 /= flux # Divide by flux, so comparison is on a relative basis. im2 /= flux printval(im2, im1, show=False) np.testing.assert_almost_equal( im2.array, im1.array, decimal=4, err_msg="PhotonDCR didn't match ChromaticAtmosphere") # Repeat with thinned bandpass and SED to check that thin still works well. im3 = galsim.ImageD(50, 50, scale=pixel_scale) thin = 0.1 # Even higher also works. But this is probably enough. thin_bandpass = bandpass.thin(thin) thin_sed = sed.thin(thin) print('len bp = %d => %d' % (len(bandpass.wave_list), len(thin_bandpass.wave_list))) print('len sed = %d => %d' % (len(sed.wave_list), len(thin_sed.wave_list))) wave_sampler = galsim.WavelengthSampler(thin_sed, thin_bandpass, rng) achrom.drawImage(image=im3, method='phot', rng=rng, surface_ops=surface_ops) im3 /= flux printval(im3, im1, show=False) np.testing.assert_almost_equal( im3.array, im1.array, decimal=4, err_msg="thinning factor %f led to 1.e-4 level inaccuracy" % thin) # Check scale_unit im4 = galsim.ImageD(50, 50, scale=pixel_scale / 60) dcr = galsim.PhotonDCR(base_wavelength=base_wavelength, zenith_angle=zenith_angle, parallactic_angle=parallactic_angle, scale_unit='arcmin', alpha=alpha) surface_ops = [wave_sampler, dcr] achrom.dilate(1. / 60).drawImage(image=im4, method='phot', rng=rng, surface_ops=surface_ops) im4 /= flux printval(im4, im1, show=False) np.testing.assert_almost_equal( im4.array, im1.array, decimal=4, err_msg="PhotonDCR with scale_unit=arcmin, didn't match") # Check some other valid options # alpha = 0 means don't do any size scaling. # obj_coord, HA and latitude are another option for setting the angles # pressure, temp, and water pressure are settable. # Also use a non-trivial WCS. wcs = galsim.FitsWCS('des_data/DECam_00154912_12_header.fits') image = galsim.Image(50, 50, wcs=wcs) bandpass = galsim.Bandpass('LSST_r.dat', wave_type='nm').thin(0.1) base_wavelength = bandpass.effective_wavelength lsst_lat = galsim.Angle.from_dms('-30:14:23.76') lsst_long = galsim.Angle.from_dms('-70:44:34.67') local_sidereal_time = 3.14 * galsim.hours # Not pi. This is the time for this observation. im5 = galsim.ImageD(50, 50, wcs=wcs) obj_coord = wcs.toWorld(im5.true_center) base_PSF = galsim.Kolmogorov(fwhm=0.9) achrom = base_PSF.withFlux(flux) dcr = galsim.PhotonDCR( base_wavelength=bandpass.effective_wavelength, obj_coord=obj_coord, HA=local_sidereal_time - obj_coord.ra, latitude=lsst_lat, pressure=72, # default is 69.328 temperature=290, # default is 293.15 H2O_pressure=0.9) # default is 1.067 #alpha=0) # default is 0, so don't need to set it. surface_ops = [wave_sampler, dcr] achrom.drawImage(image=im5, method='phot', rng=rng, surface_ops=surface_ops) im6 = galsim.ImageD(50, 50, wcs=wcs) star = galsim.DeltaFunction() * sed star = star.withFlux(flux, bandpass=bandpass) chrom_PSF = galsim.ChromaticAtmosphere( base_PSF, base_wavelength=bandpass.effective_wavelength, obj_coord=obj_coord, HA=local_sidereal_time - obj_coord.ra, latitude=lsst_lat, pressure=72, temperature=290, H2O_pressure=0.9, alpha=0) chrom = galsim.Convolve(star, chrom_PSF) chrom.drawImage(bandpass, image=im6) im5 /= flux # Divide by flux, so comparison is on a relative basis. im6 /= flux printval(im5, im6, show=False) np.testing.assert_almost_equal( im5.array, im6.array, decimal=3, err_msg="PhotonDCR with alpha=0 didn't match") # Also check invalid parameters zenith_coord = galsim.CelestialCoord(13.54 * galsim.hours, lsst_lat) assert_raises( TypeError, galsim.PhotonDCR, zenith_angle=zenith_angle, parallactic_angle=parallactic_angle) # base_wavelength is required assert_raises(TypeError, galsim.PhotonDCR, base_wavelength=500, parallactic_angle=parallactic_angle ) # zenith_angle (somehow) is required assert_raises( TypeError, galsim.PhotonDCR, 500, zenith_angle=34.4, parallactic_angle=parallactic_angle) # zenith_angle must be Angle assert_raises(TypeError, galsim.PhotonDCR, 500, zenith_angle=zenith_angle, parallactic_angle=34.5) # parallactic_angle must be Angle assert_raises(TypeError, galsim.PhotonDCR, 500, obj_coord=obj_coord, latitude=lsst_lat) # Missing HA assert_raises(TypeError, galsim.PhotonDCR, 500, obj_coord=obj_coord, HA=local_sidereal_time - obj_coord.ra) # Missing latitude assert_raises(TypeError, galsim.PhotonDCR, 500, obj_coord=obj_coord) # Need either zenith_coord, or (HA,lat) assert_raises(TypeError, galsim.PhotonDCR, 500, obj_coord=obj_coord, zenith_coord=zenith_coord, HA=local_sidereal_time - obj_coord.ra) # Can't have both HA and zenith_coord assert_raises(TypeError, galsim.PhotonDCR, 500, obj_coord=obj_coord, zenith_coord=zenith_coord, latitude=lsst_lat) # Can't have both lat and zenith_coord assert_raises(TypeError, galsim.PhotonDCR, 500, zenith_angle=zenith_angle, parallactic_angle=parallactic_angle, H20_pressure=1.) # invalid (misspelled) assert_raises(ValueError, galsim.PhotonDCR, 500, zenith_angle=zenith_angle, parallactic_angle=parallactic_angle, scale_unit='inches') # invalid scale_unit # Invalid to use dcr without some way of setting wavelengths. assert_raises(galsim.GalSimError, achrom.drawImage, im2, method='phot', surface_ops=[dcr])
def test_dcr_moments(): """Check that DCR gets the direction of the moment changes correct for some simple geometries. i.e. Basically check the sign conventions used in the DCR code. """ # First, the basics. # 1. DCR shifts blue photons closer to zenith, because the index of refraction larger. # cf. http://lsstdesc.github.io/chroma/ # 2. Galsim models profiles as seen from Earth with North up (and therefore East left). # 3. Hour angle is negative when the object is in the east (soon after rising, say), # zero when crossing the zenith meridian, and then positive to the west. # Use g-band, where the effect is more dramatic across the band than in redder bands. # Also use a reference wavelength significantly to the red, so there should be a net # overall shift towards zenith as well as a shear along the line to zenith. bandpass = galsim.Bandpass('LSST_g.dat', 'nm').thin(0.1) base_wavelength = 600 # > red end of g band # Uniform across the band is fine for this. sed = galsim.SED('1', wave_type='nm', flux_type='fphotons') rng = galsim.BaseDeviate(31415) wave_sampler = galsim.WavelengthSampler(sed, bandpass, rng) star = galsim.Kolmogorov(fwhm=0.3, flux=1.e6) # 10^6 photons should be enough. im = galsim.ImageD( 50, 50, scale=0.05) # Small pixel scale, so shift is many pixels. ra = 0 * galsim.degrees # Completely irrelevant here. lat = -20 * galsim.degrees # Also doesn't really matter much. # 1. HA < 0, Dec < lat Spot should be shifted up and right. e2 > 0. dcr = galsim.PhotonDCR(base_wavelength=base_wavelength, HA=-2 * galsim.hours, latitude=lat, obj_coord=galsim.CelestialCoord( ra, lat - 20 * galsim.degrees)) surface_ops = [wave_sampler, dcr] star.drawImage(image=im, method='phot', rng=rng, surface_ops=surface_ops) moments = galsim.utilities.unweighted_moments(im, origin=im.true_center) print('1. HA < 0, Dec < lat: ', moments) assert moments['My'] > 0 # up assert moments['Mx'] > 0 # right assert moments['Mxy'] > 0 # e2 > 0 # 2. HA = 0, Dec < lat Spot should be shifted up. e1 < 0, e2 ~= 0. dcr = galsim.PhotonDCR(base_wavelength=base_wavelength, HA=0 * galsim.hours, latitude=lat, obj_coord=galsim.CelestialCoord( ra, lat - 20 * galsim.degrees)) surface_ops = [wave_sampler, dcr] star.drawImage(image=im, method='phot', rng=rng, surface_ops=surface_ops) moments = galsim.utilities.unweighted_moments(im, origin=im.true_center) print('2. HA = 0, Dec < lat: ', moments) assert moments['My'] > 0 # up assert abs(moments['Mx']) < 0.05 # not left or right assert moments['Mxx'] < moments['Myy'] # e1 < 0 assert abs(moments['Mxy']) < 0.1 # e2 ~= 0 # 3. HA > 0, Dec < lat Spot should be shifted up and left. e2 < 0. dcr = galsim.PhotonDCR(base_wavelength=base_wavelength, HA=2 * galsim.hours, latitude=lat, obj_coord=galsim.CelestialCoord( ra, lat - 20 * galsim.degrees)) surface_ops = [wave_sampler, dcr] star.drawImage(image=im, method='phot', rng=rng, surface_ops=surface_ops) moments = galsim.utilities.unweighted_moments(im, origin=im.true_center) print('3. HA > 0, Dec < lat: ', moments) assert moments['My'] > 0 # up assert moments['Mx'] < 0 # left assert moments['Mxy'] < 0 # e2 < 0 # 4. HA < 0, Dec = lat Spot should be shifted right. e1 > 0, e2 ~= 0. dcr = galsim.PhotonDCR(base_wavelength=base_wavelength, HA=-2 * galsim.hours, latitude=lat, obj_coord=galsim.CelestialCoord(ra, lat)) surface_ops = [wave_sampler, dcr] star.drawImage(image=im, method='phot', rng=rng, surface_ops=surface_ops) moments = galsim.utilities.unweighted_moments(im, origin=im.true_center) print('4. HA < 0, Dec = lat: ', moments) assert abs(moments['My'] ) < 1. # not up or down (Actually slightly down in the south.) assert moments['Mx'] > 0 # right assert moments['Mxx'] > moments['Myy'] # e1 > 0 assert abs( moments['Mxy'] ) < 2. # e2 ~= 0 (Actually slightly negative because of curvature.) # 5. HA = 0, Dec = lat Spot should not be shifted. e1 ~= 0, e2 ~= 0. dcr = galsim.PhotonDCR(base_wavelength=base_wavelength, HA=0 * galsim.hours, latitude=lat, obj_coord=galsim.CelestialCoord(ra, lat)) surface_ops = [wave_sampler, dcr] star.drawImage(image=im, method='phot', rng=rng, surface_ops=surface_ops) moments = galsim.utilities.unweighted_moments(im, origin=im.true_center) print('5. HA = 0, Dec = lat: ', moments) assert abs(moments['My']) < 0.05 # not up or down assert abs(moments['Mx']) < 0.05 # not left or right assert abs(moments['Mxx'] - moments['Myy']) < 0.1 # e1 ~= 0 assert abs(moments['Mxy']) < 0.1 # e2 ~= 0 # 6. HA > 0, Dec = lat Spot should be shifted left. e1 > 0, e2 ~= 0. dcr = galsim.PhotonDCR(base_wavelength=base_wavelength, HA=2 * galsim.hours, latitude=lat, obj_coord=galsim.CelestialCoord(ra, lat)) surface_ops = [wave_sampler, dcr] star.drawImage(image=im, method='phot', rng=rng, surface_ops=surface_ops) moments = galsim.utilities.unweighted_moments(im, origin=im.true_center) print('6. HA > 0, Dec = lat: ', moments) assert abs(moments['My'] ) < 1. # not up or down (Actually slightly down in the south.) assert moments['Mx'] < 0 # left assert moments['Mxx'] > moments['Myy'] # e1 > 0 assert abs( moments['Mxy'] ) < 2. # e2 ~= 0 (Actually slgihtly positive because of curvature.) # 7. HA < 0, Dec > lat Spot should be shifted down and right. e2 < 0. dcr = galsim.PhotonDCR(base_wavelength=base_wavelength, HA=-2 * galsim.hours, latitude=lat, obj_coord=galsim.CelestialCoord( ra, lat + 20 * galsim.degrees)) surface_ops = [wave_sampler, dcr] star.drawImage(image=im, method='phot', rng=rng, surface_ops=surface_ops) moments = galsim.utilities.unweighted_moments(im, origin=im.true_center) print('7. HA < 0, Dec > lat: ', moments) assert moments['My'] < 0 # down assert moments['Mx'] > 0 # right assert moments['Mxy'] < 0 # e2 < 0 # 8. HA = 0, Dec > lat Spot should be shifted down. e1 < 0, e2 ~= 0. dcr = galsim.PhotonDCR(base_wavelength=base_wavelength, HA=0 * galsim.hours, latitude=lat, obj_coord=galsim.CelestialCoord( ra, lat + 20 * galsim.degrees)) surface_ops = [wave_sampler, dcr] star.drawImage(image=im, method='phot', rng=rng, surface_ops=surface_ops) moments = galsim.utilities.unweighted_moments(im, origin=im.true_center) print('8. HA = 0, Dec > lat: ', moments) assert moments['My'] < 0 # down assert abs(moments['Mx']) < 0.05 # not left or right assert moments['Mxx'] < moments['Myy'] # e1 < 0 assert abs(moments['Mxy']) < 0.1 # e2 ~= 0 # 9. HA > 0, Dec > lat Spot should be shifted down and left. e2 > 0. dcr = galsim.PhotonDCR(base_wavelength=base_wavelength, HA=2 * galsim.hours, latitude=lat, obj_coord=galsim.CelestialCoord( ra, lat + 20 * galsim.degrees)) surface_ops = [wave_sampler, dcr] star.drawImage(image=im, method='phot', rng=rng, surface_ops=surface_ops) moments = galsim.utilities.unweighted_moments(im, origin=im.true_center) print('9. HA > 0, Dec > lat: ', moments) assert moments['My'] < 0 # down assert moments['Mx'] < 0 # left assert moments['Mxy'] > 0 # e2 > 0
def drawObject(self, gsObject): """ Draw an astronomical object on all of the relevant FITS files. @param [in] gsObject is an instantiation of the GalSimCelestialObject class carrying all of the information for the object whose image is to be drawn @param [out] outputString is a string denoting which detectors the astronomical object illumines, suitable for output in the GalSim InstanceCatalog """ # find the detectors which the astronomical object illumines outputString, \ detectorList, \ centeredObj = self.findAllDetectors(gsObject) # Make sure this object is marked as "drawn" since we only # care that this method has been called for this object. self.drawn_objects.add(gsObject.uniqueId) # Compute the realized object fluxes (as drawn from the # corresponding Poisson distribution) for each band and return # right away if all values are zero in order to save compute. fluxes = [gsObject.flux(bandpassName) for bandpassName in self.bandpassDict] realized_fluxes = [galsim.PoissonDeviate(self._rng, mean=f)() for f in fluxes] if all([f == 0 for f in realized_fluxes]): return outputString if len(detectorList) == 0: # there is nothing to draw return outputString self._addNoiseAndBackground(detectorList) # Create a surface operation to sample incident angles and a # galsim.SED object for sampling the wavelengths of the # incident photons. fratio = 1.234 # From https://www.lsst.org/scientists/keynumbers obscuration = 0.606 # (8.4**2 - 6.68**2)**0.5 / 8.4 angles = galsim.FRatioAngles(fratio, obscuration, self._rng) sed_lut = galsim.LookupTable(x=gsObject.sed.wavelen, f=gsObject.sed.flambda) gs_sed = galsim.SED(sed_lut, wave_type='nm', flux_type='flambda', redshift=0.) local_hour_angle \ = self.getHourAngle(self.obs_metadata.mjd.TAI, self.obs_metadata.pointingRA)*galsim.degrees obs_latitude = self.observatory.getLatitude().asDegrees()*galsim.degrees ra_obs, dec_obs = observedFromPupilCoords(gsObject.xPupilRadians, gsObject.yPupilRadians, obs_metadata=self.obs_metadata) obj_coord = galsim.CelestialCoord(ra_obs*galsim.degrees, dec_obs*galsim.degrees) for bandpassName, realized_flux in zip(self.bandpassDict, realized_fluxes): gs_bandpass = self.gs_bandpass_dict[bandpassName] waves = galsim.WavelengthSampler(sed=gs_sed, bandpass=gs_bandpass, rng=self._rng) dcr = galsim.PhotonDCR(base_wavelength=gs_bandpass.effective_wavelength, HA=local_hour_angle, latitude=obs_latitude, obj_coord=obj_coord) # Set the object flux to the value realized from the # Poisson distribution. obj = centeredObj.withFlux(realized_flux) for detector in detectorList: name = self._getFileName(detector=detector, bandpassName=bandpassName) xPix, yPix = detector.camera_wrapper\ .pixelCoordsFromPupilCoords(gsObject.xPupilRadians, gsObject.yPupilRadians, chipName=detector.name, obs_metadata=self.obs_metadata) # Ensure the rng used by the sensor object is set to the desired state. self.sensor[detector.name].rng.reset(self._rng) surface_ops = [waves, dcr, angles] # Desired position to draw the object. image_pos = galsim.PositionD(xPix, yPix) # Find a postage stamp region to draw onto. Use (sky # noise)/3. as the nominal minimum surface brightness # for rendering an extended object. keep_sb_level = np.sqrt(self.sky_bg_per_pixel)/3. bounds = self.getStampBounds(gsObject, realized_flux, image_pos, keep_sb_level, 3*keep_sb_level) # Ensure the bounds of the postage stamp lie within the image. bounds = bounds & self.detectorImages[name].bounds if bounds.isDefined(): # offset is relative to the "true" center of the postage stamp. offset = image_pos - bounds.true_center obj.drawImage(method='phot', offset=offset, rng=self._rng, maxN=int(1e6), image=self.detectorImages[name][bounds], sensor=self.sensor[detector.name], surface_ops=surface_ops, add_to_image=True, poisson_flux=False, gain=detector.photParams.gain) # If we are writing centroid files,store the entry. if self.centroid_base_name is not None: centroid_tuple = (detector.fileName, bandpassName, gsObject.uniqueId, gsObject.flux(bandpassName), xPix, yPix) self.centroid_list.append(centroid_tuple) self.write_checkpoint() return outputString