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 self.assertRaises(ValueError, HealpixSlicer, nside=3) 

88 

89 

90class TestHealpixSlicerEqual(unittest.TestCase): 

91 

92 def setUp(self): 

93 self.nside = 16 

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

95 nvalues = 10000 

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

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

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

99 random=22) 

100 self.testslicer.setupSlicer(self.dv) 

101 

102 def tearDown(self): 

103 del self.testslicer 

104 del self.dv 

105 self.testslicer = None 

106 

107 def testSlicerEquivalence(self): 

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

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

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

111 self.assertEqual(self.testslicer, testslicer2) 

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

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

114 self.assertNotEqual(self.testslicer, testslicer2) 

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

116 

117 

118class TestHealpixSlicerIteration(unittest.TestCase): 

119 

120 def setUp(self): 

121 self.nside = 8 

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

123 nvalues = 10000 

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

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

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

127 random=33) 

128 self.testslicer.setupSlicer(self.dv) 

129 

130 def tearDown(self): 

131 del self.testslicer 

132 self.testslicer = None 

133 

134 def testIteration(self): 

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

136 npix = hp.nside2npix(self.nside) 

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

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

139 ra = s['slicePoint']['ra'] 

140 dec = s['slicePoint']['dec'] 

141 self.assertGreaterEqual(ra, 0) 

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

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

144 self.assertLessEqual(dec, np.pi) 

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

146 # so add one to check end point 

147 self.assertEqual(i+1, npix) 

148 

149 def testGetItem(self): 

150 """Test getting indexed value.""" 

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

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

153 

154 

155class TestHealpixSlicerSlicing(unittest.TestCase): 

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

157 

158 def setUp(self): 

159 self.nside = 8 

160 self.radius = 1.8 

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

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

163 radius=self.radius) 

164 nvalues = 10000 

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

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

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

168 random=44) 

169 

170 def tearDown(self): 

171 del self.testslicer 

172 self.testslicer = None 

173 

174 def testSlicing(self): 

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

176 # Test that slicing fails before setupSlicer 

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

178 # Set up and test actual slicing. 

179 self.testslicer.setupSlicer(self.dv) 

180 for s in self.testslicer: 

181 ra = s['slicePoint']['ra'] 

182 dec = s['slicePoint']['dec'] 

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

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

185 sidxs = s['idxs'] 

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

187 if len(sidxs) > 0: 

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

189 sidxs = np.sort(sidxs) 

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

191 

192 

193class TestHealpixChipGap(unittest.TestCase): 

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

195 

196 def setUp(self): 

197 self.nside = 8 

198 self.radius = 2.041 

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

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

201 radius=self.radius, useCamera=True, 

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

203 nvalues = 1000 

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

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

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

207 random=55) 

208 

209 def tearDown(self): 

210 del self.testslicer 

211 self.testslicer = None 

212 

213 def testSlicing(self): 

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

215 # Test that slicing fails before setupSlicer 

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

217 # Set up and test actual slicing. 

218 self.testslicer.setupSlicer(self.dv) 

219 for s in self.testslicer: 

220 ra = s['slicePoint']['ra'] 

221 dec = s['slicePoint']['dec'] 

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

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

224 sidxs = s['idxs'] 

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

226 if len(sidxs) > 0: 

227 for indx in sidxs: 

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

229 

230 

231class TestHealpixSlicerPlotting(unittest.TestCase): 

232 

233 def setUp(self): 

234 rng = np.random.RandomState(713244122) 

235 self.nside = 16 

236 self.radius = 1.8 

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

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

239 nvalues = 10000 

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

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

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

243 random=66) 

244 self.testslicer.setupSlicer(self.dv) 

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

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

247 fill_value=self.testslicer.badval) 

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

249 idxs = b['idxs'] 

250 if len(idxs) > 0: 

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

252 else: 

253 self.metricdata.mask[i] = True 

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

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

256 fill_value=self.testslicer.badval) 

257 

258 def tearDown(self): 

259 del self.testslicer 

260 self.testslicer = None 

261 

262 

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

264 pass 

265 

266 

267def setup_module(module): 

268 lsst.utils.tests.init() 

269 

270 

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

272 lsst.utils.tests.init() 

273 unittest.main()