Coverage for tests/testFWHM.py : 25%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from builtins import range
2import numpy as np
3import os
4import unittest
5import galsim
6import tempfile
7import shutil
8import lsst.utils.tests
9from lsst.utils import getPackageDir
10import lsst.afw.image as afwImage
11from lsst.sims.utils.CodeUtilities import sims_clean_up
12from lsst.sims.utils import ObservationMetaData, arcsecFromRadians
13from lsst.sims.catalogs.db import fileDBObject
14from lsst.sims.GalSimInterface import GalSimStars, SNRdocumentPSF
15from lsst.sims.GalSimInterface import Kolmogorov_and_Gaussian_PSF
16from lsst.sims.GalSimInterface import GalSimCameraWrapper
18#from lsst.sims.coordUtils.utils import ReturnCamera
20from testUtils import create_text_catalog
22ROOT = os.path.abspath(os.path.dirname(__file__))
25def setup_module(module):
26 lsst.utils.tests.init()
29class fwhmFileDBObj(fileDBObject):
30 idColKey = 'test_id'
31 objectTypeId = 88
32 tableid = 'test'
33 raColName = 'ra'
34 decColName = 'dec'
35 # sedFilename
37 columns = [('raJ2000', 'ra*PI()/180.0', np.float),
38 ('decJ2000', 'dec*PI()/180.0', np.float),
39 ('magNorm', 'mag_norm', np.float)]
42class fwhmCat(GalSimStars):
43 bandpassNames = ['u']
45 default_columns = GalSimStars.default_columns
47 default_columns += [('sedFilename', 'sed_flat.txt', (str, 12)),
48 ('properMotionRa', 0.0, np.float),
49 ('properMotionDec', 0.0, np.float),
50 ('radialVelocity', 0.0, np.float),
51 ('parallax', 0.0, np.float)]
53@unittest.skip('ReturnCamera deprecated - need replacement')
54class GalSimFwhmTest(unittest.TestCase):
56 longMessage = True
58 @classmethod
59 def tearDownClass(cls):
60 sims_clean_up()
62 def verify_fwhm(self, fileName, fwhm, pixel_scale):
63 """
64 Read in a FITS image with one object on it and verify that that object
65 has the expected Full Width at Half Maximum. This is done by fitting
66 the image to the double Gaussian PSF model implemented in
67 SNRdocumentPSF(), varying the FWHM.
69 @param [in] fileName is the name of the FITS image
71 @param [in] fwhm is the expected Full Width at Half Maximum in arcseconds
73 @param [in] pixel_scale in arcsec
75 This method will raise an exception if the measured Full Width at Half Maximum
76 deviates from the expected value by more than ten percent.
77 """
78 im = afwImage.ImageF(fileName).getArray()
79 maxFlux = im.max()
80 self.assertGreater(maxFlux, 100.0) # make sure the image is not blank
82 im_flat = im.flatten()
83 x_arr = np.array([ii % im.shape[0] for ii in range(len(im_flat))])
84 y_arr = np.array([ii // im.shape[0] for ii in range(len(im_flat))])
86 valid_pix = np.where(im_flat>1.0e-20)
87 im_flat = im_flat[valid_pix].astype(float)
88 x_arr = x_arr[valid_pix]
89 y_arr = y_arr[valid_pix]
91 total_flux = im_flat.sum()
93 x_center = (x_arr.astype(float)*im_flat).sum()/total_flux
94 y_center = (y_arr.astype(float)*im_flat).sum()/total_flux
96 chisq_best = None
97 fwhm_best = None
99 total_flux = im_flat.sum()
101 for fwhm_test in np.arange(0.9*fwhm, 1.1*fwhm, 0.01*fwhm):
102 alpha = fwhm_test/2.3835
104 dd = np.power(x_arr-x_center,2).astype(float) + np.power(y_arr-y_center, 2).astype(float)
105 dd *= np.power(pixel_scale, 2)
107 sigma = alpha
108 g1 = np.exp(-0.5*dd/(sigma*sigma))/(sigma*sigma*2.0*np.pi)
110 sigma = 2.0*alpha
111 g2 = np.exp(-0.5*dd/(sigma*sigma))/(sigma*sigma*2.0*np.pi)
113 model = 0.909*(g1 + 0.1*g2)*pixel_scale*pixel_scale
114 norm = model.sum()
115 model *= (total_flux/norm)
116 chisq = np.power((im_flat-model), 2).sum()
118 if chisq_best is None or np.isnan(chisq_best) or chisq<chisq_best:
119 chisq_best = chisq
120 fwhm_best = fwhm_test
122 msg = '\ntrue fwhm: %e\nfitted fwhm: %e\nchisq: %e\npixel scale: %e\n' \
123 % (fwhm, fwhm_best, chisq_best,pixel_scale)
124 self.assertLess(np.abs(fwhm-fwhm_best), 0.015*fwhm, msg=msg)
126 def testFwhmOfImage(self):
127 """
128 Test that GalSim generates images with the expected Full Width at Half Maximum.
129 """
130 scratchDir = tempfile.mkdtemp(dir=ROOT, prefix='testFwhmOfImage-')
131 catName = os.path.join(scratchDir, 'fwhm_test_Catalog.dat')
132 imageRoot = os.path.join(scratchDir, 'fwhm_test_Image')
133 dbFileName = os.path.join(scratchDir, 'fwhm_test_InputCatalog.dat')
135 baseDir = os.path.join(getPackageDir('sims_GalSimInterface'), 'tests', 'cameraData')
137 # instantiate a test camera with pixel_scale = 0.02 arcsec/pixel
138 camera = ReturnCamera(baseDir)
140 detector = camera[0]
141 detName = detector.getName()
142 imageName = '%s_%s_u.fits' % (imageRoot, detName)
144 obs = ObservationMetaData(pointingRA = 75.0,
145 pointingDec = -12.0,
146 boundType = 'circle',
147 boundLength = 4.0,
148 rotSkyPos = 33.0,
149 mjd = 49250.0)
151 create_text_catalog(obs, dbFileName, np.array([3.0]),
152 np.array([1.0]), mag_norm=[13.0])
154 db = fwhmFileDBObj(dbFileName, runtable='test')
156 for fwhm in (0.1, 0.14):
158 cat = fwhmCat(db, obs_metadata=obs)
159 cat.camera_wrapper = GalSimCameraWrapper(camera)
161 psf = SNRdocumentPSF(fwhm=fwhm, pixel_scale=0.02)
162 cat.setPSF(psf)
164 cat.write_catalog(catName)
165 cat.write_images(nameRoot=imageRoot)
167 self.verify_fwhm(imageName, fwhm, 0.02)
169 if os.path.exists(catName):
170 os.unlink(catName)
172 if os.path.exists(imageName):
173 os.unlink(imageName)
175 if os.path.exists(dbFileName):
176 os.unlink(dbFileName)
177 if os.path.exists(scratchDir):
178 shutil.rmtree(scratchDir)
180@unittest.skip('ReturnCamera deprecated - need replacement')
181class KolmogrovGaussianTestCase(unittest.TestCase):
182 """
183 Just test that the Kolmogorov_and_Gaussian_PSF runs
184 """
186 @classmethod
187 def tearDownClass(cls):
188 sims_clean_up()
190 def testKolmogorovGaussianPSF(self):
191 scratchDir = tempfile.mkdtemp(prefix='testKolmogorovGaussianPSF', dir=ROOT)
192 catName = os.path.join(scratchDir, 'kolmogorov_gaussian_test_Catalog.dat')
193 imageRoot = os.path.join(scratchDir, 'kolmogorov_gaussian_test_Image')
194 dbFileName = os.path.join(scratchDir, 'kolmogorov_gaussian_test_InputCatalog.dat')
196 baseDir = os.path.join(getPackageDir('sims_GalSimInterface'), 'tests', 'cameraData')
198 # instantiate a test camera with pixel_scale = 0.02 arcsec/pixel
199 camera = ReturnCamera(baseDir)
201 detector = camera[0]
202 detName = detector.getName()
203 imageName = '%s_%s_u.fits' % (imageRoot, detName)
205 obs = ObservationMetaData(pointingRA = 75.0,
206 pointingDec = -12.0,
207 boundType = 'circle',
208 boundLength = 4.0,
209 rotSkyPos = 33.0,
210 mjd = 49250.0)
212 create_text_catalog(obs, dbFileName, np.array([3.0]),
213 np.array([1.0]), mag_norm=[13.0])
215 db = fwhmFileDBObj(dbFileName, runtable='test')
217 cat = fwhmCat(db, obs_metadata=obs)
218 cat.camera_wrapper = GalSimCameraWrapper(camera)
220 psf = Kolmogorov_and_Gaussian_PSF(rawSeeing=0.7, airmass=1.05, band='g')
221 cat.setPSF(psf)
223 cat.write_catalog(catName)
224 cat.write_images(nameRoot=imageRoot)
226 if os.path.exists(scratchDir):
227 shutil.rmtree(scratchDir)
230class AnalyticPsfTestCase(unittest.TestCase):
231 """
232 Test the FWHM of our PSF models when using GalSim's Fourier-space
233 image generation, not pixel shooting.
234 """
236 longMessage = True
238 def verify_analytic_fwhm(self, fwhm_in, pixel_scale, im):
239 """
240 Verify the FWHM of an object generated by GalSim's analytic image generation
241 (i.e. not by photonshooting). This is done by fitting the image to the double
242 Gaussian PSF model implemented in SNRdocumentPSF(), varying the FWHM.
244 Parameters
245 ----------
246 fwhm_in is the expected FWHM in arcsec
248 pixel_scale is the pixel scale in arcsec
250 im is a numpy array containing the image fluxes (i.e. the output of galsim.Image.array)
252 Returns
253 -------
255 This method will raise an exception if the measured Full Width at Half Maximum
256 deviates from the expected value by more than one.
257 """
258 maxFlux = im.max()
259 #self.assertGreater(maxFlux, 100.0) # make sure the image is not blank
261 im_flat = im.flatten()
262 x_arr = np.array([ii % im.shape[0] for ii in range(len(im_flat))])
263 y_arr = np.array([ii // im.shape[0] for ii in range(len(im_flat))])
265 valid_pix = np.where(im_flat>1.0e-20)
266 im_flat = im_flat[valid_pix].astype(float)
267 x_arr = x_arr[valid_pix]
268 y_arr = y_arr[valid_pix]
270 total_flux = im_flat.sum()
272 x_center = (x_arr.astype(float)*im_flat).sum()/total_flux
273 y_center = (y_arr.astype(float)*im_flat).sum()/total_flux
275 chisq_best = None
276 fwhm_best = None
278 total_flux = im_flat.sum()
280 for fwhm_test in np.arange(0.01*fwhm_in, 3.0*fwhm_in, 0.01*fwhm_in):
281 alpha = fwhm_test/2.3835
283 dd = np.power(x_arr-x_center,2).astype(float) + np.power(y_arr-y_center, 2).astype(float)
284 dd *= np.power(pixel_scale, 2)
286 sigma = alpha
287 g1 = np.exp(-0.5*dd/(sigma*sigma))/(sigma*sigma*2.0*np.pi)
289 sigma = 2.0*alpha
290 g2 = np.exp(-0.5*dd/(sigma*sigma))/(sigma*sigma*2.0*np.pi)
292 model = 0.909*(g1 + 0.1*g2)*pixel_scale*pixel_scale
293 norm = model.sum()
294 model *= (total_flux/norm)
295 chisq = np.power((im_flat-model), 2).sum()
297 if chisq_best is None or np.isnan(chisq_best) or chisq<chisq_best:
298 chisq_best = chisq
299 fwhm_best = fwhm_test
301 msg = '\ntrue fwhm: %e\nfitted fwhm: %e\nchisq: %e\n' \
302 % (fwhm_in, fwhm_best, chisq_best)
303 self.assertLess(np.abs(fwhm_in-fwhm_best), 0.01*fwhm_in, msg=msg)
306 def test_SNRdocumentPSF(self):
307 fwhm_in = 0.3
308 pixel_scale = 0.2
309 psf_gen = SNRdocumentPSF(fwhm=fwhm_in, pixel_scale=pixel_scale)
310 psf = psf_gen._getPSF()
311 image = galsim.ImageD(256, 256, scale=pixel_scale)
312 image = psf.drawImage(image)
313 self.verify_analytic_fwhm(fwhm_in, pixel_scale, image.array)
316class MemoryTestClass(lsst.utils.tests.MemoryTestCase):
317 pass
319if __name__ == "__main__": 319 ↛ 320line 319 didn't jump to line 320, because the condition on line 319 was never true
320 lsst.utils.tests.init()
321 unittest.main()