Hide keyboard shortcuts

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 

17 

18#from lsst.sims.coordUtils.utils import ReturnCamera 

19 

20from testUtils import create_text_catalog 

21 

22ROOT = os.path.abspath(os.path.dirname(__file__)) 

23 

24 

25def setup_module(module): 

26 lsst.utils.tests.init() 

27 

28 

29class fwhmFileDBObj(fileDBObject): 

30 idColKey = 'test_id' 

31 objectTypeId = 88 

32 tableid = 'test' 

33 raColName = 'ra' 

34 decColName = 'dec' 

35 # sedFilename 

36 

37 columns = [('raJ2000', 'ra*PI()/180.0', np.float), 

38 ('decJ2000', 'dec*PI()/180.0', np.float), 

39 ('magNorm', 'mag_norm', np.float)] 

40 

41 

42class fwhmCat(GalSimStars): 

43 bandpassNames = ['u'] 

44 

45 default_columns = GalSimStars.default_columns 

46 

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)] 

52 

53@unittest.skip('ReturnCamera deprecated - need replacement') 

54class GalSimFwhmTest(unittest.TestCase): 

55 

56 longMessage = True 

57 

58 @classmethod 

59 def tearDownClass(cls): 

60 sims_clean_up() 

61 

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. 

68 

69 @param [in] fileName is the name of the FITS image 

70 

71 @param [in] fwhm is the expected Full Width at Half Maximum in arcseconds 

72 

73 @param [in] pixel_scale in arcsec 

74 

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 

81 

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))]) 

85 

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] 

90 

91 total_flux = im_flat.sum() 

92 

93 x_center = (x_arr.astype(float)*im_flat).sum()/total_flux 

94 y_center = (y_arr.astype(float)*im_flat).sum()/total_flux 

95 

96 chisq_best = None 

97 fwhm_best = None 

98 

99 total_flux = im_flat.sum() 

100 

101 for fwhm_test in np.arange(0.9*fwhm, 1.1*fwhm, 0.01*fwhm): 

102 alpha = fwhm_test/2.3835 

103 

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) 

106 

107 sigma = alpha 

108 g1 = np.exp(-0.5*dd/(sigma*sigma))/(sigma*sigma*2.0*np.pi) 

109 

110 sigma = 2.0*alpha 

111 g2 = np.exp(-0.5*dd/(sigma*sigma))/(sigma*sigma*2.0*np.pi) 

112 

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() 

117 

118 if chisq_best is None or np.isnan(chisq_best) or chisq<chisq_best: 

119 chisq_best = chisq 

120 fwhm_best = fwhm_test 

121 

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) 

125 

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') 

134 

135 baseDir = os.path.join(getPackageDir('sims_GalSimInterface'), 'tests', 'cameraData') 

136 

137 # instantiate a test camera with pixel_scale = 0.02 arcsec/pixel 

138 camera = ReturnCamera(baseDir) 

139 

140 detector = camera[0] 

141 detName = detector.getName() 

142 imageName = '%s_%s_u.fits' % (imageRoot, detName) 

143 

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) 

150 

151 create_text_catalog(obs, dbFileName, np.array([3.0]), 

152 np.array([1.0]), mag_norm=[13.0]) 

153 

154 db = fwhmFileDBObj(dbFileName, runtable='test') 

155 

156 for fwhm in (0.1, 0.14): 

157 

158 cat = fwhmCat(db, obs_metadata=obs) 

159 cat.camera_wrapper = GalSimCameraWrapper(camera) 

160 

161 psf = SNRdocumentPSF(fwhm=fwhm, pixel_scale=0.02) 

162 cat.setPSF(psf) 

163 

164 cat.write_catalog(catName) 

165 cat.write_images(nameRoot=imageRoot) 

166 

167 self.verify_fwhm(imageName, fwhm, 0.02) 

168 

169 if os.path.exists(catName): 

170 os.unlink(catName) 

171 

172 if os.path.exists(imageName): 

173 os.unlink(imageName) 

174 

175 if os.path.exists(dbFileName): 

176 os.unlink(dbFileName) 

177 if os.path.exists(scratchDir): 

178 shutil.rmtree(scratchDir) 

179 

180@unittest.skip('ReturnCamera deprecated - need replacement') 

181class KolmogrovGaussianTestCase(unittest.TestCase): 

182 """ 

183 Just test that the Kolmogorov_and_Gaussian_PSF runs 

184 """ 

185 

186 @classmethod 

187 def tearDownClass(cls): 

188 sims_clean_up() 

189 

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') 

195 

196 baseDir = os.path.join(getPackageDir('sims_GalSimInterface'), 'tests', 'cameraData') 

197 

198 # instantiate a test camera with pixel_scale = 0.02 arcsec/pixel 

199 camera = ReturnCamera(baseDir) 

200 

201 detector = camera[0] 

202 detName = detector.getName() 

203 imageName = '%s_%s_u.fits' % (imageRoot, detName) 

204 

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) 

211 

212 create_text_catalog(obs, dbFileName, np.array([3.0]), 

213 np.array([1.0]), mag_norm=[13.0]) 

214 

215 db = fwhmFileDBObj(dbFileName, runtable='test') 

216 

217 cat = fwhmCat(db, obs_metadata=obs) 

218 cat.camera_wrapper = GalSimCameraWrapper(camera) 

219 

220 psf = Kolmogorov_and_Gaussian_PSF(rawSeeing=0.7, airmass=1.05, band='g') 

221 cat.setPSF(psf) 

222 

223 cat.write_catalog(catName) 

224 cat.write_images(nameRoot=imageRoot) 

225 

226 if os.path.exists(scratchDir): 

227 shutil.rmtree(scratchDir) 

228 

229 

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 """ 

235 

236 longMessage = True 

237 

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. 

243 

244 Parameters 

245 ---------- 

246 fwhm_in is the expected FWHM in arcsec 

247 

248 pixel_scale is the pixel scale in arcsec 

249 

250 im is a numpy array containing the image fluxes (i.e. the output of galsim.Image.array) 

251 

252 Returns 

253 ------- 

254 

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 

260 

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))]) 

264 

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] 

269 

270 total_flux = im_flat.sum() 

271 

272 x_center = (x_arr.astype(float)*im_flat).sum()/total_flux 

273 y_center = (y_arr.astype(float)*im_flat).sum()/total_flux 

274 

275 chisq_best = None 

276 fwhm_best = None 

277 

278 total_flux = im_flat.sum() 

279 

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 

282 

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) 

285 

286 sigma = alpha 

287 g1 = np.exp(-0.5*dd/(sigma*sigma))/(sigma*sigma*2.0*np.pi) 

288 

289 sigma = 2.0*alpha 

290 g2 = np.exp(-0.5*dd/(sigma*sigma))/(sigma*sigma*2.0*np.pi) 

291 

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() 

296 

297 if chisq_best is None or np.isnan(chisq_best) or chisq<chisq_best: 

298 chisq_best = chisq 

299 fwhm_best = fwhm_test 

300 

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) 

304 

305 

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) 

314 

315 

316class MemoryTestClass(lsst.utils.tests.MemoryTestCase): 

317 pass 

318 

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()