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 zip 

2import numpy as np 

3import os 

4import unittest 

5import tempfile 

6import shutil 

7import lsst.utils.tests 

8from lsst.utils import getPackageDir 

9import lsst.afw.image as afwImage 

10from lsst.sims.utils.CodeUtilities import sims_clean_up 

11from lsst.sims.utils import ObservationMetaData, radiansFromArcsec 

12from lsst.sims.catalogs.db import fileDBObject 

13from lsst.sims.GalSimInterface import GalSimGalaxies 

14from lsst.sims.GalSimInterface import GalSimCameraWrapper 

15from lsst.sims.coordUtils import _raDecFromPixelCoords 

16 

17#afrom lsst.sims.coordUtils.utils import ReturnCamera 

18 

19from testUtils import create_text_catalog 

20 

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

22 

23 

24def setup_module(module): 

25 lsst.utils.tests.init() 

26 

27 

28class paFileDBObj(fileDBObject): 

29 idColKey = 'test_id' 

30 objectTypeId = 88 

31 tableid = 'test' 

32 raColName = 'ra' 

33 decColName = 'dec' 

34 # sedFilename 

35 

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

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

38 ('halfLightRadius', 'hlr*PI()/648000.0', np.float), 

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

40 ('positionAngle', 'pa*PI()/180.0', np.float)] 

41 

42 

43class paCat(GalSimGalaxies): 

44 bandpassNames = ['u'] 

45 default_columns = [('sedFilename', 'sed_flat.txt', (str, 12)), 

46 ('magNorm', 21.0, float), 

47 ('galacticAv', 0.1, float), 

48 ('galacticRv', 3.1, float), 

49 ('galSimType', 'sersic', (str, 11)), 

50 ('internalAv', 0.1, float), 

51 ('internalRv', 3.1, float), 

52 ('redshift', 0.0, float), 

53 ('majorAxis', radiansFromArcsec(1.0), float), 

54 ('minorAxis', radiansFromArcsec(0.5), float), 

55 ('sindex', 4.0, float), 

56 ('npoints', 0, int), 

57 ('gamma1', 0.0, float), 

58 ('gamma2', 0.0, float), 

59 ('kappa', 0.0, float), 

60 ] 

61 

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

63class GalSimPositionAngleTest(unittest.TestCase): 

64 

65 @classmethod 

66 def tearDownClass(cls): 

67 sims_clean_up() 

68 

69 def get_position_angle(self, imageName, afwCamera, afwDetector, 

70 obs_metadata, epoch): 

71 """ 

72 Read in a FITS image containing one extended object. 

73 

74 Determine its north and east axes by examining how RA and Dec change 

75 with pixel position. 

76 

77 Determine the semi-major axis of the object by treating the distribution 

78 of flux as a covariance matrix and finding its eigen vectors. 

79 

80 Return the angle between the semi-major axis and the north axis of 

81 the image 

82 

83 @param [in] imageName is the name of the FITS image to be read 

84 

85 @param [in] afwCamera is an afw.cameraGeom.Camera 

86 

87 @param [in] afwDetector is an afw.cameraGeom.Detector 

88 

89 @param [in] obs_metadata is an ObservationMetaData describing the 

90 pointing of the telescope 

91 

92 @param [in] epoch is the epoch in Julian years of the equinox against 

93 which RA and Dec are measured 

94 

95 @param [out] the position angle of the object in the image in degrees 

96 """ 

97 

98 im = afwImage.ImageF(imageName).getArray() 

99 activePixels = np.where(im > 1.0e-10) 

100 self.assertGreater(len(activePixels), 0) 

101 xPixList = activePixels[1] 

102 yPixList = activePixels[0] 

103 

104 xCenterPix = np.array([im.shape[1]/2]) 

105 yCenterPix = np.array([im.shape[0]/2]) 

106 

107 raCenter, decCenter = _raDecFromPixelCoords(xCenterPix, yCenterPix, 

108 [afwDetector.getName()], 

109 camera=afwCamera, 

110 obs_metadata=obs_metadata, 

111 epoch=epoch) 

112 

113 xCenterP1 = xCenterPix+1 

114 yCenterP1 = yCenterPix+1 

115 raCenterP1, decCenterP1 = _raDecFromPixelCoords(xCenterP1, yCenterP1, 

116 [afwDetector.getName()], 

117 camera=afwCamera, 

118 obs_metadata=obs_metadata, 

119 epoch=epoch) 

120 

121 # find the angle between the (1,1) vector in pixel space and the 

122 # north axis of the image 

123 theta = np.arctan2((raCenterP1[0]-raCenter[0]), decCenterP1[0]-decCenter[0]) 

124 

125 # rotate the (1,1) vector in pixel space so that it is pointing 

126 # along the north axis 

127 north = np.array([np.cos(theta)-np.sin(theta), np.cos(theta)+np.sin(theta)]) 

128 north = north/np.sqrt(north[0]*north[0]+north[1]*north[1]) 

129 

130 # find the east axis of the image 

131 east = np.array([north[1], -1.0*north[0]]) 

132 

133 # now find the covariance matrix of the x, y pixel space distribution 

134 # of flux on the image 

135 maxPixel = np.array([im.argmax()%im.shape[1], im.argmax()/im.shape[1]]) 

136 

137 xx = np.array([im[iy][ix]*np.power(ix-maxPixel[0], 2) 

138 for ix, iy in zip(xPixList, yPixList)]).sum() 

139 

140 xy = np.array([im[iy][ix]*(ix-maxPixel[0])*(iy-maxPixel[1]) 

141 for ix, iy in zip(xPixList, yPixList)]).sum() 

142 

143 yy = np.array([im[iy][ix]*(iy-maxPixel[1])*(iy-maxPixel[1]) 

144 for ix, iy in zip(xPixList, yPixList)]).sum() 

145 

146 covar = np.array([[xx, xy], [xy, yy]]) 

147 

148 # find the eigen vectors of this covarinace matrix; 

149 # treat the one with the largest eigen value as the 

150 # semi-major axis of the object 

151 eigenVals, eigenVecs = np.linalg.eig(covar) 

152 

153 iMax = eigenVals.argmax() 

154 majorAxis = eigenVecs[:, iMax] 

155 

156 majorAxis = majorAxis/np.sqrt(majorAxis[0]*majorAxis[0]+majorAxis[1]*majorAxis[1]) 

157 

158 # return the angle between the north axis of the image 

159 # and the semi-major axis of the object 

160 cosTheta = np.dot(majorAxis, north) 

161 sinTheta = np.dot(majorAxis, east) 

162 

163 theta = np.arctan2(sinTheta, cosTheta) 

164 

165 return np.degrees(theta) 

166 

167 def testPositionAngle(self): 

168 """ 

169 Test that GalSim is generating images with the correct position angle 

170 by creating a FITS image with one extended source in it. Measure 

171 the angle between the semi-major axis of the source and the north 

172 axis of the image. Throw an exception if that angle differs 

173 from the expected position angle by more than 2 degrees. 

174 """ 

175 scratchDir = tempfile.mkdtemp(dir=ROOT, prefix='testPositionAngle-') 

176 catName = os.path.join(scratchDir, 'pa_test_Catalog.dat') 

177 imageRoot = os.path.join(scratchDir, 'pa_test_Image') 

178 dbFileName = os.path.join(scratchDir, 'pa_test_InputCatalog.dat') 

179 

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

181 camera = ReturnCamera(baseDir) 

182 detector = camera[0] 

183 detName = detector.getName() 

184 

185 rng = np.random.RandomState(42) 

186 paList = rng.random_sample(7)*360.0 

187 rotSkyPosList = rng.random_sample(77)*360.0 

188 

189 for pa, rotSkyPos in zip(paList, rotSkyPosList): 

190 

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

192 

193 obs = ObservationMetaData(pointingRA = 75.0, 

194 pointingDec = -12.0, 

195 boundType = 'circle', 

196 boundLength = 4.0, 

197 rotSkyPos = rotSkyPos, 

198 mjd = 49250.0) 

199 

200 create_text_catalog(obs, dbFileName, 

201 rng.random_sample(1)*20.0-10.0, 

202 rng.random_sample(1)*20.0-10.0, 

203 pa=[pa], 

204 mag_norm=[17.0]) 

205 

206 db = paFileDBObj(dbFileName, runtable='test') 

207 

208 cat = paCat(db, obs_metadata=obs) 

209 cat.camera_wrapper = GalSimCameraWrapper(camera) 

210 

211 cat.write_catalog(catName) 

212 cat.write_images(nameRoot=imageRoot) 

213 

214 paTest = self.get_position_angle(imageName, camera, detector, obs, 2000.0) 

215 

216 # need to compare against all angles displaced by either 180 or 360 degrees 

217 # from expected answer 

218 deviation = np.abs(np.array([pa-paTest, 

219 pa-180.0-paTest, 

220 pa+180.0-paTest, 

221 pa-360.0-paTest, 

222 pa+360.0-paTest])).min() 

223 

224 self.assertLess(deviation, 3.0) 

225 

226 if os.path.exists(catName): 

227 os.unlink(catName) 

228 if os.path.exists(dbFileName): 

229 os.unlink(dbFileName) 

230 if os.path.exists(imageName): 

231 os.unlink(imageName) 

232 

233 if os.path.exists(scratchDir): 

234 shutil.rmtree(scratchDir) 

235 

236 

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

238 pass 

239 

240if __name__ == "__main__": 240 ↛ 241line 240 didn't jump to line 241, because the condition on line 240 was never true

241 lsst.utils.tests.init() 

242 unittest.main()