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 matplotlib 

3matplotlib.use("Agg") 

4import numpy as np 

5import numpy.lib.recfunctions as rfn 

6import numpy.ma as ma 

7import unittest 

8import healpy as hp 

9from lsst.sims.maf.slicers.healpixSlicer import HealpixSlicer 

10import lsst.utils.tests 

11 

12 

13def makeDataValues(size=100, minval=0., maxval=1., ramin=0, ramax=2*np.pi, 

14 decmin=-np.pi, decmax=np.pi, random=1172): 

15 """Generate a simple array of numbers, evenly arranged between min/max, 

16 in 1 dimensions (optionally sorted), together with RA/Dec values 

17 for each data value.""" 

18 data = [] 

19 # Generate data values min - max. 

20 datavalues = np.arange(0, size, dtype='float') 

21 datavalues *= (float(maxval) - float(minval)) / (datavalues.max() - datavalues.min()) 

22 datavalues += minval 

23 rng = np.random.RandomState(random) 

24 randorder = rng.rand(size) 

25 randind = np.argsort(randorder) 

26 datavalues = datavalues[randind] 

27 datavalues = np.array(list(zip(datavalues)), dtype=[('testdata', 'float')]) 

28 data.append(datavalues) 

29 # Generate RA/Dec values equally spaces on sphere between ramin/max, decmin/max. 

30 ra = np.arange(0, size, dtype='float') 

31 ra *= (float(ramax) - float(ramin)) / (ra.max() - ra.min()) 

32 randorder = rng.rand(size) 

33 randind = np.argsort(randorder) 

34 ra = ra[randind] 

35 ra = np.array(list(zip(ra)), dtype=[('ra', 'float')]) 

36 data.append(ra) 

37 v = np.arange(0, size, dtype='float') 

38 v *= ((np.cos(decmax+np.pi) + 1.)/2.0 - (np.cos(decmin+np.pi)+1.)/2.0) / (v.max() - v.min()) 

39 v += (np.cos(decmin+np.pi)+1.)/2.0 

40 dec = np.arccos(2*v-1) - np.pi 

41 randorder = rng.rand(size) 

42 randind = np.argsort(randorder) 

43 dec = dec[randind] 

44 dec = np.array(list(zip(dec)), dtype=[('dec', 'float')]) 

45 data.append(dec) 

46 # Add in rotation angle 

47 rot = rng.rand(len(dec))*2*np.pi 

48 data.append(np.array(rot, dtype=[('rotSkyPos', 'float')])) 

49 mjd = np.arange(len(dec))*.1 

50 data.append(np.array(mjd, dtype=[('observationStartMJD', 'float')])) 

51 data = rfn.merge_arrays(data, flatten=True, usemask=False) 

52 return data 

53 

54 

55def calcDist_vincenty(RA1, Dec1, RA2, Dec2): 

56 """Calculates distance on a sphere using the Vincenty formula. 

57 Give this function RA/Dec values in radians. Returns angular distance(s), in radians. 

58 Note that since this is all numpy, you could input arrays of RA/Decs.""" 

59 D1 = (np.cos(Dec2)*np.sin(RA2-RA1))**2 + \ 

60 (np.cos(Dec1)*np.sin(Dec2) - 

61 np.sin(Dec1)*np.cos(Dec2)*np.cos(RA2-RA1))**2 

62 D1 = np.sqrt(D1) 

63 D2 = (np.sin(Dec1)*np.sin(Dec2) + 

64 np.cos(Dec1)*np.cos(Dec2)*np.cos(RA2-RA1)) 

65 D = np.arctan2(D1, D2) 

66 return D 

67 

68 

69class TestHealpixSlicerSetup(unittest.TestCase): 

70 

71 def testSlicertype(self): 

72 """Test instantiation of slicer sets slicer type as expected.""" 

73 testslicer = HealpixSlicer(nside=16, verbose=False) 

74 self.assertEqual(testslicer.slicerName, testslicer.__class__.__name__) 

75 self.assertEqual(testslicer.slicerName, 'HealpixSlicer') 

76 

77 def testNsidesNbins(self): 

78 """Test that number of sides passed to slicer produces expected number of bins.""" 

79 nsides = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] 

80 npixx = [12, 48, 192, 768, 3072, 12288, 49152, 196608, 786432, 3145728] 

81 for nside, npix in zip(nsides, npixx): 

82 testslicer = HealpixSlicer(nside=nside, verbose=False) 

83 self.assertEqual(testslicer.nslice, npix) 

84 

85 def testNsidesError(self): 

86 """Test that if passed an incorrect value for nsides that get expected exception.""" 

87 # FIXME: This used to throw an exception. We comment it out for now. 

88 # self.assertRaises(ValueError, HealpixSlicer, nside=3) 

89 

90 

91class TestHealpixSlicerEqual(unittest.TestCase): 

92 

93 def setUp(self): 

94 self.nside = 16 

95 self.testslicer = HealpixSlicer(nside=self.nside, verbose=False, lonCol='ra', latCol='dec') 

96 nvalues = 10000 

97 self.dv = makeDataValues(size=nvalues, minval=0., maxval=1., 

98 ramin=0, ramax=2*np.pi, 

99 decmin=-np.pi, decmax=0, 

100 random=22) 

101 self.testslicer.setupSlicer(self.dv) 

102 

103 def tearDown(self): 

104 del self.testslicer 

105 del self.dv 

106 self.testslicer = None 

107 

108 def testSlicerEquivalence(self): 

109 """Test that slicers are marked equal when appropriate, and unequal when appropriate.""" 

110 # Note that they are judged equal based on nsides (not on data in ra/dec spatial tree). 

111 testslicer2 = HealpixSlicer(nside=self.nside, verbose=False, lonCol='ra', latCol='dec') 

112 self.assertEqual(self.testslicer, testslicer2) 

113 assert((self.testslicer != testslicer2) is False) 

114 testslicer2 = HealpixSlicer(nside=self.nside/2.0, verbose=False, lonCol='ra', latCol='dec') 

115 self.assertNotEqual(self.testslicer, testslicer2) 

116 assert((self.testslicer != testslicer2) is True) 

117 

118 

119class TestHealpixSlicerIteration(unittest.TestCase): 

120 

121 def setUp(self): 

122 self.nside = 8 

123 self.testslicer = HealpixSlicer(nside=self.nside, verbose=False, lonCol='ra', latCol='dec') 

124 nvalues = 10000 

125 self.dv = makeDataValues(size=nvalues, minval=0., maxval=1., 

126 ramin=0, ramax=2*np.pi, 

127 decmin=-np.pi, decmax=0, 

128 random=33) 

129 self.testslicer.setupSlicer(self.dv) 

130 

131 def tearDown(self): 

132 del self.testslicer 

133 self.testslicer = None 

134 

135 def testIteration(self): 

136 """Test iteration goes through expected range and ra/dec are in expected range (radians).""" 

137 npix = hp.nside2npix(self.nside) 

138 for i, s in enumerate(self.testslicer): 

139 self.assertEqual(i, s['slicePoint']['sid']) 

140 ra = s['slicePoint']['ra'] 

141 dec = s['slicePoint']['dec'] 

142 self.assertGreaterEqual(ra, 0) 

143 self.assertLessEqual(ra, 2*np.pi) 

144 self.assertGreaterEqual(dec, -np.pi) 

145 self.assertLessEqual(dec, np.pi) 

146 # npix would count starting at 1, while i counts starting at 0 .. 

147 # so add one to check end point 

148 self.assertEqual(i+1, npix) 

149 

150 def testGetItem(self): 

151 """Test getting indexed value.""" 

152 for i, s in enumerate(self.testslicer): 

153 np.testing.assert_equal(self.testslicer[i], s) 

154 

155 

156class TestHealpixSlicerSlicing(unittest.TestCase): 

157 # Note that this is really testing baseSpatialSlicer, as slicing is done there for healpix grid 

158 

159 def setUp(self): 

160 self.nside = 8 

161 self.radius = 1.8 

162 self.testslicer = HealpixSlicer(nside=self.nside, verbose=False, 

163 lonCol='ra', latCol='dec', latLonDeg=False, 

164 radius=self.radius) 

165 nvalues = 10000 

166 self.dv = makeDataValues(size=nvalues, minval=0., maxval=1., 

167 ramin=0, ramax=2*np.pi, 

168 decmin=-np.pi, decmax=0, 

169 random=44) 

170 

171 def tearDown(self): 

172 del self.testslicer 

173 self.testslicer = None 

174 

175 def testSlicing(self): 

176 """Test slicing returns (all) data points which are within 'radius' of bin point.""" 

177 # Test that slicing fails before setupSlicer 

178 self.assertRaises(NotImplementedError, self.testslicer._sliceSimData, 0) 

179 # Set up and test actual slicing. 

180 self.testslicer.setupSlicer(self.dv) 

181 for s in self.testslicer: 

182 ra = s['slicePoint']['ra'] 

183 dec = s['slicePoint']['dec'] 

184 distances = calcDist_vincenty(ra, dec, self.dv['ra'], self.dv['dec']) 

185 didxs = np.where(distances <= np.radians(self.radius)) 

186 sidxs = s['idxs'] 

187 self.assertEqual(len(sidxs), len(didxs[0])) 

188 if len(sidxs) > 0: 

189 didxs = np.sort(didxs[0]) 

190 sidxs = np.sort(sidxs) 

191 np.testing.assert_equal(self.dv['testdata'][didxs], self.dv['testdata'][sidxs]) 

192 

193 

194class TestHealpixChipGap(unittest.TestCase): 

195 # Note that this is really testing baseSpatialSlicer, as slicing is done there for healpix grid 

196 

197 def setUp(self): 

198 self.nside = 8 

199 self.radius = 2.041 

200 self.testslicer = HealpixSlicer(nside=self.nside, verbose=False, 

201 lonCol='ra', latCol='dec', latLonDeg=False, 

202 radius=self.radius, useCamera=True, 

203 chipNames=['R:1,1 S:1,1']) 

204 nvalues = 1000 

205 self.dv = makeDataValues(size=nvalues, minval=0., maxval=1., 

206 ramin=0, ramax=2*np.pi, 

207 decmin=-np.pi, decmax=0, 

208 random=55) 

209 

210 def tearDown(self): 

211 del self.testslicer 

212 self.testslicer = None 

213 

214 def testSlicing(self): 

215 """Test slicing returns (most) data points which are within 'radius' of bin point.""" 

216 # Test that slicing fails before setupSlicer 

217 self.assertRaises(NotImplementedError, self.testslicer._sliceSimData, 0) 

218 # Set up and test actual slicing. 

219 self.testslicer.setupSlicer(self.dv) 

220 for s in self.testslicer: 

221 ra = s['slicePoint']['ra'] 

222 dec = s['slicePoint']['dec'] 

223 distances = calcDist_vincenty(ra, dec, self.dv['ra'], self.dv['dec']) 

224 didxs = np.where(distances <= np.radians(self.radius)) 

225 sidxs = s['idxs'] 

226 self.assertLessEqual(len(sidxs), len(didxs[0])) 

227 if len(sidxs) > 0: 

228 for indx in sidxs: 

229 self.assertIn(self.dv['testdata'][indx], self.dv['testdata'][didxs]) 

230 

231 

232class TestHealpixSlicerPlotting(unittest.TestCase): 

233 

234 def setUp(self): 

235 rng = np.random.RandomState(713244122) 

236 self.nside = 16 

237 self.radius = 1.8 

238 self.testslicer = HealpixSlicer(nside=self.nside, verbose=False, latLonDeg=False, 

239 lonCol='ra', latCol='dec', radius=self.radius) 

240 nvalues = 10000 

241 self.dv = makeDataValues(size=nvalues, minval=0., maxval=1., 

242 ramin=0, ramax=2*np.pi, 

243 decmin=-np.pi, decmax=0, 

244 random=66) 

245 self.testslicer.setupSlicer(self.dv) 

246 self.metricdata = ma.MaskedArray(data=np.zeros(len(self.testslicer), dtype='float'), 

247 mask=np.zeros(len(self.testslicer), 'bool'), 

248 fill_value=self.testslicer.badval) 

249 for i, b in enumerate(self.testslicer): 

250 idxs = b['idxs'] 

251 if len(idxs) > 0: 

252 self.metricdata.data[i] = np.mean(self.dv['testdata'][idxs]) 

253 else: 

254 self.metricdata.mask[i] = True 

255 self.metricdata2 = ma.MaskedArray(data=rng.rand(len(self.testslicer)), 

256 mask=np.zeros(len(self.testslicer), 'bool'), 

257 fill_value=self.testslicer.badval) 

258 

259 def tearDown(self): 

260 del self.testslicer 

261 self.testslicer = None 

262 

263 

264class TestMemory(lsst.utils.tests.MemoryTestCase): 

265 pass 

266 

267 

268def setup_module(module): 

269 lsst.utils.tests.init() 

270 

271 

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

273 lsst.utils.tests.init() 

274 unittest.main()