Coverage for tests/test_trixel.py : 8%

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
1import unittest
2import lsst.utils.tests
3from lsst.utils import getPackageDir
4from lsst.sims.utils import findHtmid, trixelFromHtmid
5from lsst.sims.utils import HalfSpace, basic_trixels
6from lsst.sims.utils import halfSpaceFromRaDec, levelFromHtmid
7from lsst.sims.utils import halfSpaceFromPoints
8from lsst.sims.utils import intersectHalfSpaces
9from lsst.sims.utils import getAllTrixels
10from lsst.sims.utils import arcsecFromRadians
11from lsst.sims.utils.htmModule import _findHtmid_fast
12from lsst.sims.utils.htmModule import _findHtmid_slow
14import numpy as np
15import os
16import numbers
18from lsst.sims.utils import sphericalFromCartesian, cartesianFromSpherical
19from lsst.sims.utils import rotAboutY, rotAboutX, rotAboutZ
20from lsst.sims.utils import angularSeparation, _angularSeparation
23def setup_module(module):
24 lsst.utils.tests.init()
27def trixel_intersects_half_space(trix, hspace):
28 """
29 This is a brute force method to determine whether a trixel
30 is inside, or at least intersects, a halfspace.
31 """
32 if hspace.phi > 0.25*np.pi:
33 raise RuntimeError("trixel_intersects_half_space is not safe for "
34 "large HalfSpaces")
36 # if any of the trixel's corners are within the
37 # HalfSpace, return True
38 raRad, decRad = sphericalFromCartesian(hspace.vector)
39 for corner in trix.corners:
40 raRad1, decRad1 = sphericalFromCartesian(corner)
41 if _angularSeparation(raRad, decRad, raRad1, decRad1) < hspace.phi:
42 return True
44 # if the trixel contains the HalfSpace's center,
45 # return True
46 if trix.contains_pt(hspace.vector):
47 return True
49 sinphi = np.abs(np.sin(hspace.phi))
51 # Iterate over each pair of corners (c1, c2). For each pair,
52 # construct a coordinate basis in which +z is in the
53 # direction of c3, and +x is along the
54 # unit vector defining c_i such that the angle
55 # phi of c_j in the x,y plane is positive. This coordinate
56 # system is such that the trixel edge defined by c1, c2 is
57 # now along the equator of the unit sphere. Find the point
58 # of closest approach of the HalfSpace's center to the equator.
59 # If that point is between c1 and c2, return True.
60 for i_c_1 in range(3):
61 c1 = trix.corners[i_c_1]
62 for i_c_2 in range(3):
63 if i_c_2 <= i_c_1:
64 continue
65 c2 = trix.corners[i_c_2]
66 i_c_3 = 3 - (i_c_1+i_c_2)
67 c3 = trix.corners[i_c_3]
68 assert i_c_3 != i_c_2
69 assert i_c_3 != i_c_1
70 assert i_c_1 != i_c_2
72 z_axis = np.array([c1[1]*c2[2]-c1[2]*c2[1],
73 c2[0]*c1[2]-c1[0]*c2[2],
74 c1[0]*c2[1]-c2[0]*c1[1]])
75 z_axis = z_axis/np.sqrt((z_axis**2).sum())
77 if np.dot(z_axis, c3) < 0.0:
78 z_axis *= -1.0
80 assert np.abs(1.0-np.dot(z_axis, z_axis)) < 1.0e-10
81 assert np.abs(1.0-np.dot(c1, c1)) < 1.0e-10
82 assert np.abs(1.0-np.dot(c2, c2)) < 1.0e-10
83 assert np.abs(np.dot(z_axis, c1)) < 1.0e-10
84 assert np.abs(np.dot(z_axis, c2)) < 1.0e-10
86 # if the dot product of the center of the HalfSpace
87 # with the z axis of the new coordinate system is
88 # greater than the sine of the radius of the
89 # halfspace, then there is no way that the halfspace
90 # intersects the equator of the unit sphere in this
91 # coordinate system
92 if np.abs(np.dot(z_axis, hspace.vector)) > sinphi:
93 continue
95 x_axis = c1
96 y_axis = -1.0*np.array([x_axis[1]*z_axis[2]-x_axis[2]*z_axis[1],
97 z_axis[0]*x_axis[2]-x_axis[0]*z_axis[2],
98 x_axis[0]*z_axis[1]-z_axis[0]*x_axis[1]])
100 cos_a = np.dot(x_axis, c2)
101 sin_a = np.dot(y_axis, c2)
103 if sin_a < 0.0:
104 x_axis = c2
105 y_axis = -1.0*np.array([x_axis[1]*z_axis[2]-x_axis[2]*z_axis[1],
106 z_axis[0]*x_axis[2]-x_axis[0]*z_axis[2],
107 x_axis[0]*z_axis[1]-z_axis[0]*x_axis[1]])
109 cos_a = np.dot(x_axis, c1)
110 sin_a = np.dot(y_axis, c1)
112 assert cos_a >= 0.0
113 assert sin_a >= 0.0
114 assert np.abs(1.0-cos_a**2-sin_a**2) < 1.0e-10
115 assert np.abs(np.dot(x_axis, z_axis)) < 1.0e-10
116 assert np.abs(np.dot(x_axis, y_axis)) < 1.0e-10
117 assert np.abs(np.dot(y_axis, z_axis)) < 1.0e-10
119 x_center = np.dot(x_axis, hspace.vector)
121 # if the x-coordinate of the HalfSpace's center is
122 # negative, the HalfSpace is on the opposite side
123 # of the unit sphere; ignore this pair c1, c2
124 if x_center < 0.0:
125 continue
127 y_center = np.dot(y_axis, hspace.vector)
129 # tan_a is the tangent of the angle between
130 # the x_axis and the other trixel corner in
131 # the x, y plane
132 tan_a = sin_a/cos_a
134 # tan_extreme is the tangent of the angle in
135 # the x, y plane defining the point of closest
136 # approach of the HalfSpace's center to the
137 # equator. If this point is between c1, c2,
138 # return True.
139 tan_extreme = y_center/x_center
140 if tan_extreme > 0.0 and tan_extreme < tan_a:
141 return True
143 return False
146class HalfSpaceTest(unittest.TestCase):
148 longMessage = True
150 def test_half_space_contains_pt(self):
151 hs = HalfSpace(np.array([0.0, 0.0, 1.0]), 0.1)
152 nhs = HalfSpace(np.array([0.0, 0.0, -1.0]), -0.1)
153 theta = np.arcsin(0.1)
154 rng = np.random.RandomState(88)
155 n_tests = 200
156 ra_list = rng.random_sample(n_tests)*2.0*np.pi
157 dec_list = rng.random_sample(n_tests)*(0.5*np.pi-theta)+theta
158 for ra, dec, in zip(ra_list, dec_list):
159 xyz = cartesianFromSpherical(ra, dec)
160 self.assertTrue(hs.contains_pt(xyz))
161 self.assertFalse(nhs.contains_pt(xyz))
163 ra_list = rng.random_sample(n_tests)*2.0*np.pi
164 dec_list = theta - rng.random_sample(n_tests)*(0.5*np.pi+theta)
165 for ra, dec, in zip(ra_list, dec_list):
166 xyz = cartesianFromSpherical(ra, dec)
167 self.assertFalse(hs.contains_pt(xyz))
168 self.assertTrue(nhs.contains_pt(xyz))
170 hs = HalfSpace(np.array([1.0, 0.0, 0.0]), 0.2)
171 nhs = HalfSpace(np.array([-1.0, 0.0, 0.0]), -0.2)
172 theta = np.arcsin(0.2)
173 ra_list = rng.random_sample(n_tests)*2.0*np.pi
174 dec_list = rng.random_sample(n_tests)*(0.5*np.pi-theta)+theta
175 for ra, dec in zip(ra_list, dec_list):
176 xyz_rot = cartesianFromSpherical(ra, dec)
177 xyz = rotAboutY(xyz_rot, 0.5*np.pi)
178 self.assertTrue(hs.contains_pt(xyz))
179 self.assertFalse(nhs.contains_pt(xyz))
181 ra_list = rng.random_sample(n_tests)*2.0*np.pi
182 dec_list = theta - rng.random_sample(n_tests)*(0.5*np.pi+theta)
183 for ra, dec, in zip(ra_list, dec_list):
184 xyz_rot = cartesianFromSpherical(ra, dec)
185 xyz = rotAboutY(xyz_rot, 0.5*np.pi)
186 self.assertFalse(hs.contains_pt(xyz))
187 self.assertTrue(nhs.contains_pt(xyz))
189 vv = np.array([0.5*np.sqrt(2), -0.5*np.sqrt(2), 0.0])
190 hs = HalfSpace(vv, 0.3)
191 nhs = HalfSpace(-1.0*vv, -0.3)
192 theta = np.arcsin(0.3)
193 ra_list = rng.random_sample(n_tests)*2.0*np.pi
194 dec_list = rng.random_sample(n_tests)*(0.5*np.pi-theta)+theta
196 for ra, dec in zip(ra_list, dec_list):
197 xyz_rot = cartesianFromSpherical(ra, dec)
198 xyz_rot = rotAboutX(xyz_rot, 0.5*np.pi)
199 xyz = rotAboutZ(xyz_rot, 0.25*np.pi)
200 self.assertTrue(hs.contains_pt(xyz))
201 self.assertFalse(nhs.contains_pt(xyz))
203 ra_list = rng.random_sample(n_tests)*2.0*np.pi
204 dec_list = theta - rng.random_sample(n_tests)*(0.5*np.pi+theta)
205 for ra, dec, in zip(ra_list, dec_list):
206 xyz_rot = cartesianFromSpherical(ra, dec)
207 xyz_rot = rotAboutX(xyz_rot, 0.5*np.pi)
208 xyz = rotAboutZ(xyz_rot, 0.25*np.pi)
209 self.assertFalse(hs.contains_pt(xyz))
210 self.assertTrue(nhs.contains_pt(xyz))
212 def test_halfspace_contains_pt_scaled(self):
213 """
214 Test that HalfSpace.contains_pt returns the same answer
215 for points on and off the unit sphere
216 """
217 vv = np.array([0.5*np.sqrt(2), -0.5*np.sqrt(2), 0.0])
218 hs = HalfSpace(vv, 0.3)
220 ct_inside = 0
221 ct_outside = 0
222 rng = np.random.RandomState(8812)
223 random_pts = rng.random_sample((100, 3))*5.0
224 for pt in random_pts:
225 norm = np.sqrt(np.power(pt, 2).sum())
226 self.assertGreater(np.abs(1.0-norm), 0.01)
227 unnormed_ans = hs.contains_pt(pt)
228 normed_pt = pt/norm
229 normed_ans = hs.contains_pt(normed_pt)
230 self.assertEqual(unnormed_ans, normed_ans)
232 if normed_ans:
233 ct_inside += 1
234 else:
235 ct_outside += 1
237 self.assertGreater(ct_inside, 0)
238 self.assertGreater(ct_outside, 0)
240 def test_halfspace_contains_trixel(self):
242 # test half space that is on the equator wher N3 and S0 meet
243 hs = HalfSpace(np.array([1.0, 1.0, 0.0]), 0.8)
244 for tx in basic_trixels:
245 status = hs.contains_trixel(basic_trixels[tx])
246 msg = 'Failed on %s' % tx
247 if tx not in ('S0', 'N3'):
248 self.assertEqual(status, 'outside', msg=msg)
249 else:
250 self.assertEqual(status, 'partial', msg=msg)
252 # test halfspace that is centered on vertex where S0, S3, N0, N3 meet
253 hs = HalfSpace(np.array([1.0, 0.0, 0.0]), 0.8)
254 for tx in basic_trixels:
255 status = hs.contains_trixel(basic_trixels[tx])
256 msg = 'Failed on %s' % tx
257 if tx not in ('S0', 'S3', 'N0', 'N3'):
258 self.assertEqual(status, 'outside', msg=msg)
259 else:
260 self.assertEqual(status, 'partial', msg=msg)
262 # test halfspace fully contained in N3
263 hs = HalfSpace(np.array([1.0, 1.0, 1.0]), 0.9)
264 for tx in basic_trixels:
265 status = hs.contains_trixel(basic_trixels[tx])
266 msg = 'Failed on %s' % tx
267 if tx != 'N3':
268 self.assertEqual(status, 'outside', msg=msg)
269 else:
270 self.assertEqual(status, 'partial', msg=msg)
272 # test halfspace that totally contains N3
273 ra, dec = basic_trixels['N3'].get_center()
274 hs = HalfSpace(np.array([1.0, 1.0, 1.0]), np.cos(0.31*np.pi))
275 for tx in basic_trixels:
276 status = hs.contains_trixel(basic_trixels[tx])
277 msg = 'Failed on %s' % tx
278 if tx == 'N3':
279 self.assertEqual(status, 'full', msg=msg)
280 elif tx in ('N1', 'N2', 'N0', 'S0', 'S1', 'S3'):
281 self.assertEqual(status, 'partial', msg=msg)
282 else:
283 self.assertEqual(status, 'outside', msg=msg)
285 def test_half_space_eq(self):
286 """
287 Test that __eq__() works for HalfSpace
288 """
289 vv = np.array([1.0, 0.9, 2.4])
290 hs1 = HalfSpace(vv, 0.1)
291 hs2 = HalfSpace(2.0*vv, 0.1)
292 self.assertEqual(hs1, hs2)
293 hs2 = HalfSpace(vv, 0.09)
294 self.assertNotEqual(hs1, hs2)
295 hs2 = HalfSpace(vv-1.0e-4*np.array([1.0, 0.0, 0.0]), 0.1)
296 self.assertNotEqual(hs1, hs2)
298 def test_findAllTrixels_radius(self):
299 """
300 Test the method that attempts to find all of the trixels
301 inside a given half space by approximating the angular
302 scale of the trixels and verifying that all returned
303 trixels are within radius+angular scale of the center
304 of the half space.
305 """
306 level = 5
308 # approximate the linear angular scale (in degrees)
309 # of a trixel grid using the fact that there are
310 # 8*4**(level-1) trixels in the grid as per equation 2.5 of
311 #
312 # https://www.microsoft.com/en-us/research/wp-content/uploads/2005/09/tr-2005-123.pdf
313 angular_scale = np.sqrt(4.0*np.pi*(180.0/np.pi)**2/(8.0*4.0**(level-1)))
315 ra = 43.0
316 dec = 22.0
317 radius = 20.0
318 half_space = halfSpaceFromRaDec(ra, dec, radius)
319 trixel_list = half_space.findAllTrixels(level)
320 self.assertGreater(len(trixel_list), 2)
322 # first, check that all of the returned trixels are
323 # inside the HalfSpace
324 good_htmid_list = []
325 for i_limit, limits in enumerate(trixel_list):
327 # verify that the tuples have been sorted by
328 # htmid_min
329 if i_limit > 0:
330 self.assertGreater(limits[0], trixel_list[i_limit-1][1])
332 for htmid in range(limits[0], limits[1]+1):
333 test_trixel = trixelFromHtmid(htmid)
334 ra_trix, dec_trix = test_trixel.get_center()
335 good_htmid_list.append(htmid)
336 self.assertNotEqual(half_space.contains_trixel(test_trixel),
337 'outside')
339 # check that the returned trixels are within
340 # radius+angular_scale of the center of the HalfSpace
341 self.assertLess(angularSeparation(ra, dec, ra_trix, dec_trix),
342 radius+angular_scale)
344 # next, verify that all of the possible trixels that
345 # were not returned are outside the HalfSpace
346 for base_htmid in range(8, 16):
347 htmid_0 = base_htmid << 2*(level-1)
348 self.assertEqual(levelFromHtmid(htmid_0), level)
349 for ii in range(2**(2*level-2)):
350 htmid = htmid_0 + ii
351 self.assertEqual(levelFromHtmid(htmid), level)
352 if htmid not in good_htmid_list:
353 test_trixel = trixelFromHtmid(htmid)
354 self.assertEqual(half_space.contains_trixel(test_trixel), 'outside')
355 ra_trix, dec_trix = test_trixel.get_center()
356 self.assertGreater(angularSeparation(ra, dec, ra_trix, dec_trix),
357 radius)
359 def test_findAllTrixels_brute(self):
360 """
361 Use the method trixel_intersects_half_space defined at the
362 top of this script to verify that HalfSpace.findAllTrixels works
363 """
364 level = 7
365 trixel_dict = getAllTrixels(level)
366 all_htmid = []
367 for htmid in trixel_dict.keys():
368 if levelFromHtmid(htmid) == level:
369 all_htmid.append(htmid)
371 hspace = halfSpaceFromRaDec(36.0, 22.1, 2.0)
373 # make sure that the two methods of determining if
374 # a HalfSpace contains a trixel (HalfSpace.contains_trixel
375 # and trixel_interects_half_space) agree
376 for htmid in all_htmid:
377 trix = trixel_dict[htmid]
378 msg = 'offending htmid %d' % htmid
379 if trixel_intersects_half_space(trix, hspace):
380 self.assertNotEqual(hspace.contains_trixel(trix), 'outside',
381 msg=msg)
382 else:
383 self.assertEqual(hspace.contains_trixel(trix), 'outside',
384 msg=msg)
386 trixel_limits = hspace.findAllTrixels(level)
387 intersecting_htmid = set()
389 # check that all of the trixels included in the limits
390 # do, in fact, intersect or exist in the HalfSpace
391 for lim in trixel_limits:
392 for htmid in range(lim[0], lim[1]+1):
393 trix = trixel_dict[htmid]
394 self.assertTrue(trixel_intersects_half_space(trix, hspace))
395 intersecting_htmid.add(htmid)
397 # check that all of the trixels not included in the limits
398 # are, in fact, outside of the HalfSpace
399 self.assertLess(len(intersecting_htmid), len(all_htmid))
400 self.assertGreater(len(intersecting_htmid), 0)
401 for htmid in all_htmid:
402 if htmid in intersecting_htmid:
403 continue
404 trix = trixel_dict[htmid]
405 self.assertFalse(trixel_intersects_half_space(trix, hspace))
407 def test_halfSpaceFromPoints(self):
408 rng = np.random.RandomState(88)
409 for ii in range(10):
410 pt1 = (rng.random_sample()*360.0, rng.random_sample()*180.0-90.0)
411 pt2 = (rng.random_sample()*360.0, rng.random_sample()*180.0-90.0)
412 pt3 = (rng.random_sample()*360.0, rng.random_sample()*180.0-90.0)
413 hs = halfSpaceFromPoints(pt1, pt2, pt3)
415 # check that the HalfSpace contains pt3
416 vv3 = cartesianFromSpherical(np.radians(pt3[0]), np.radians(pt3[1]))
417 self.assertTrue(hs.contains_pt(vv3))
419 # check that the HalfSpace encompasses 1/2 of the unit sphere
420 self.assertAlmostEqual(hs.phi, 0.5*np.pi, 10)
421 self.assertAlmostEqual(hs.dd, 0.0, 10)
423 # check that pt1 and pt2 are 90 degrees away from the center
424 # of the HalfSpace
425 vv1 = cartesianFromSpherical(np.radians(pt1[0]), np.radians(pt1[1]))
426 vv2 = cartesianFromSpherical(np.radians(pt2[0]), np.radians(pt2[1]))
427 self.assertAlmostEqual(np.dot(vv1,hs.vector), 0.0, 10)
428 self.assertAlmostEqual(np.dot(vv2,hs.vector), 0.0, 10)
430 def test_HalfSpaceIntersection(self):
432 # Test that the two roots of an intersection are the
433 # correct angular distance from the centers of the
434 # half spaces
435 ra1 = 22.0
436 dec1 = 45.0
437 rad1 = 10.0
438 ra2 = 23.5
439 dec2 = 37.9
440 rad2 = 9.2
441 hs1 = halfSpaceFromRaDec(ra1, dec1, rad1)
442 hs2 = halfSpaceFromRaDec(ra2, dec2, rad2)
443 roots = intersectHalfSpaces(hs1, hs2)
444 self.assertEqual(len(roots), 2)
445 self.assertAlmostEqual(np.sqrt(np.sum(roots[0]**2)), 1.0, 10)
446 self.assertAlmostEqual(np.sqrt(np.sum(roots[1]**2)), 1.0, 10)
447 ra_r1, dec_r1 = np.degrees(sphericalFromCartesian(roots[0]))
448 ra_r2, dec_r2 = np.degrees(sphericalFromCartesian(roots[1]))
449 dd = angularSeparation(ra1, dec1, ra_r1, dec_r1)
450 self.assertAlmostEqual(dd, rad1, 10)
451 dd = angularSeparation(ra1, dec1, ra_r2, dec_r2)
452 self.assertAlmostEqual(dd, rad1, 10)
453 dd = angularSeparation(ra2, dec2, ra_r1, dec_r1)
454 self.assertAlmostEqual(dd, rad2, 10)
455 dd = angularSeparation(ra2, dec2, ra_r2, dec_r2)
456 self.assertAlmostEqual(dd, rad2, 10)
458 # test that two non-intersecting HalfSpaces return no roots
459 hs1 = halfSpaceFromRaDec(0.0, 90.0, 1.0)
460 hs2 = halfSpaceFromRaDec(20.0, -75.0, 5.0)
461 roots = intersectHalfSpaces(hs1, hs2)
462 self.assertEqual(len(roots), 0)
464 # test that two half spaces that are inside each other
465 # return no roots
466 hs1 = halfSpaceFromRaDec(77.0, 10.0, 20.0)
467 hs2 = halfSpaceFromRaDec(75.0, 8.0, 0.2)
468 roots = intersectHalfSpaces(hs1, hs2)
469 self.assertEqual(len(roots), 0)
471 # test that two half spaces with identical centers
472 # return no roots
473 hs1 = halfSpaceFromRaDec(11.0, -23.0, 1.0)
474 hs2 = halfSpaceFromRaDec(11.0, -23.0, 0.2)
475 roots = intersectHalfSpaces(hs1, hs2)
476 self.assertEqual(len(roots), 0)
478 roots = intersectHalfSpaces(hs1, hs1)
479 self.assertEqual(len(roots), 0)
481 def test_merge_trixel_bounds(self):
482 """
483 Test that the merge_trixel_bounds method works
484 """
485 input_bound = [(1,7), (2,4), (21,35), (8,11), (36, 42), (43, 43)]
486 result = HalfSpace.merge_trixel_bounds(input_bound)
487 shld_be = [(1, 11), (21, 43)]
488 self.assertEqual(result, shld_be)
490 def test_join_trixel_bound_sets(self):
491 """
492 Test that HalfSpace.join_trixel_bound_sets works
493 """
494 b1 = [(32,47), (6,8), (11,19), (12,14), (66,73)]
495 b2 = [(35,41), (7,15), (41, 44)]
496 result = HalfSpace.join_trixel_bound_sets(b1, b2)
497 shld_be = [(7,8), (11, 15), (35,44)]
498 self.assertEqual(result, shld_be)
500 def test_contains_many_pts(self):
501 """
502 Test that HalfSpace.contains_many_pts works
503 """
504 rng = np.random.RandomState(5142)
505 n_pts = 100
506 vv_list = np.zeros((n_pts,3), dtype=float)
507 for ii in range(n_pts):
508 vv = rng.random_sample(3)-0.5
509 vv /= np.sqrt(np.sum(vv**2))
510 vv_list[ii] = vv
512 vv = rng.random_sample(3)-0.5
513 vv /= np.sqrt(np.sum(vv**2))
514 hs = HalfSpace(vv, 0.3)
515 results = hs.contains_many_pts(vv_list)
516 is_true = np.where(results)[0]
517 self.assertGreater(len(is_true), n_pts//4)
518 self.assertLess(len(is_true), 3*n_pts//4)
519 for i_vv, vv in enumerate(vv_list):
520 self.assertEqual(hs.contains_pt(vv), results[i_vv])
523class TrixelFinderTest(unittest.TestCase):
525 longMessage = True
527 def check_pt(self, pt, answer):
528 """
529 Take a Cartesian point (pt) and a known
530 htmid for that point (answer). Find the htmid
531 for the point using findHtmid and verify that
532 we get the expected answer.
533 """
534 ra, dec = sphericalFromCartesian(pt)
535 ii = findHtmid(np.degrees(ra), np.degrees(dec), 3)
536 binary = '{0:b}'.format(ii)
537 self.assertEqual(binary, answer)
539 def test_against_fatboy(self):
540 """
541 Test findHtmid against a random selection of stars from fatboy
542 """
543 dtype = np.dtype([('htmid', int), ('ra', float), ('dec', float)])
544 data = np.genfromtxt(os.path.join(getPackageDir('sims_utils'), 'tests',
545 'testData', 'htmid_test_data.txt'),
546 dtype=dtype)
547 self.assertGreater(len(data), 20)
548 for i_pt in range(len(data)):
549 htmid_test = findHtmid(data['ra'][i_pt], data['dec'][i_pt], 21)
550 self.assertEqual(htmid_test, data['htmid'][i_pt])
551 level_test = levelFromHtmid(htmid_test)
552 self.assertEqual(level_test, 21)
554 def test_findHtmid_vectorized(self):
555 """
556 Test that findHtmid works correctly on vectors
557 """
558 rng = np.random.RandomState(81723122)
559 n_samples = 1000
560 ra = rng.random_sample(n_samples)*360.0
561 dec = rng.random_sample(n_samples)*180.0-90.0
562 level = 7
563 htmid_vec = findHtmid(ra, dec, level)
564 self.assertIsInstance(htmid_vec, np.ndarray)
565 htmid_fast = _findHtmid_fast(ra, dec, level)
566 self.assertIsInstance(htmid_fast, np.ndarray)
567 np.testing.assert_array_equal(htmid_vec, htmid_fast)
568 for ii in range(n_samples):
569 htmid_slow = _findHtmid_slow(ra[ii], dec[ii], level)
570 self.assertIsInstance(htmid_slow, numbers.Number)
571 self.assertEqual(htmid_slow, htmid_vec[ii])
572 htmid_single = findHtmid(ra[ii], dec[ii], level)
573 self.assertIsInstance(htmid_single, numbers.Number)
574 self.assertEqual(htmid_single, htmid_vec[ii])
576 def test_levelFromHtmid(self):
577 """
578 Test that levelFromHtmid behaves as expected
579 """
580 for ii in range(8, 16):
581 self.assertEqual(levelFromHtmid(ii), 1)
583 self.assertEqual(levelFromHtmid(2**9+5), 4)
584 self.assertEqual(levelFromHtmid(2**15+88), 7)
586 with self.assertRaises(RuntimeError) as context:
587 levelFromHtmid(2**10)
588 self.assertIn("4+2n", context.exception.args[0])
590 for ii in range(8):
591 with self.assertRaises(RuntimeError) as context:
592 levelFromHtmid(2**10)
593 self.assertIn("4+2n", context.exception.args[0])
595 def test_trixel_finding(self):
596 """
597 Check that findHtmid works by passing in some
598 points whose htmid are known because of their
599 proximity to the corners of low-level Trixels.
600 Use check_pt to verify that findHtmid gives
601 the right answer.
602 """
603 epsilon = 1.0e-6
604 dx = np.array([epsilon, 0.0, 0.0])
605 dy = np.array([0.0, epsilon, 0.0])
606 dz = np.array([0.0, 0.0, epsilon])
608 xx = np.array([1.0, 0.0, 0.0])
609 yy = np.array([0.0, 1.0, 0.0])
610 zz = np.array([0.0, 0.0, 1.0])
612 pt = xx + dy + dz
613 # N320
614 self.check_pt(pt, '11111000')
616 pt = xx - dy + dz
617 # N000
618 self.check_pt(pt, '11000000')
620 pt = xx - dy - dz
621 # S320
622 self.check_pt(pt, '10111000')
624 pt = yy + dx + dz
625 # N300
626 self.check_pt(pt, '11110000')
628 pt = yy - dx + dz
629 # N220
630 self.check_pt(pt, '11101000')
632 pt = yy - dx - dz
633 # S100
634 self.check_pt(pt, '10010000')
636 pt = zz + dy + dx
637 # N310
638 self.check_pt(pt, '11110100')
640 pt = zz - dy + dx
641 # N010
642 self.check_pt(pt, '11000100')
644 pt = zz - dy - dx
645 # N110
646 self.check_pt(pt, '11010100')
648 pt = -xx + dz + dy
649 # N200
650 self.check_pt(pt, '11100000')
652 pt = -xx - dz + dy
653 # S120
654 self.check_pt(pt, '10011000')
656 pt = -xx - dz - dy
657 # S200
658 self.check_pt(pt, '10100000')
660 pt = -yy + dx + dz
661 # N020
662 self.check_pt(pt, '11001000')
664 pt = -yy - dx + dz
665 # N100
666 self.check_pt(pt, '11010000')
668 pt = -yy - dx - dz
669 # S220
670 self.check_pt(pt, '10101000')
672 pt = -zz + dx + dy
673 # S010
674 self.check_pt(pt, '10000100')
676 pt = -zz - dx + dy
677 # S110
678 self.check_pt(pt, '10010100')
680 pt = -zz - dx - dy
681 # S210
682 self.check_pt(pt, '10100100')
684 pt = xx + yy + zz
685 # N333
686 self.check_pt(pt, '11111111')
688 def test_trixel_from_htmid(self):
689 """
690 Check that trixelFromHtmid works by
691 finding the htmid from an RA, Dec pair,
692 instantiating the Trixel corresponding
693 to that htmid, and verifying that that
694 Trixel (and not its neighbors) contains
695 the RA, Dec pair.
696 """
697 rng = np.random.RandomState(88)
698 n_tests = 100
699 for i_test in range(n_tests):
700 pt = rng.normal(0.0, 1.0, 3)
701 ra, dec = sphericalFromCartesian(pt)
702 ra = np.degrees(ra)
703 dec = np.degrees(dec)
704 ii = findHtmid(ra, dec, 5)
705 tt = trixelFromHtmid(ii)
706 self.assertTrue(tt.contains(ra, dec))
707 tt1 = trixelFromHtmid(ii-1)
708 self.assertFalse(tt1.contains(ra, dec))
709 tt2 = trixelFromHtmid(ii+1)
710 self.assertFalse(tt2.contains(ra, dec))
712 def test_trixel_eq_ne(self):
713 """
714 Test that the __eq__ and __ne__ operators on the Trixel class work
715 """
716 t1 = trixelFromHtmid(8*16+1)
717 t2 = trixelFromHtmid(8*16+1)
718 self.assertEqual(t1, t2)
719 t3 = trixelFromHtmid(8*16+3)
720 self.assertNotEqual(t1, t3)
721 self.assertTrue(t1 == t2)
722 self.assertFalse(t1 == t3)
723 self.assertTrue(t1 != t3)
724 self.assertFalse(t2 == t3)
725 self.assertTrue(t2 != t3)
727 def test_get_all_trixels(self):
728 """
729 Test method to get all trixels up to a certain level
730 """
731 max_level = 5
732 n_trixel_per_level = {}
733 n_trixel_per_level[0] = 0
734 for level in range(1, max_level+1):
735 n_trixel_per_level[level] = 8*(4**(level-1))
737 trixel_dict = getAllTrixels(max_level)
738 n_found = {}
739 for level in range(max_level+1):
740 n_found[level] = 0
742 for htmid in trixel_dict:
743 level = levelFromHtmid(htmid)
744 n_found[level] += 1
746 # verify that the correct number of trixels were
747 # found per level
748 for level in n_found:
749 msg = 'failed on level %d' % level
750 self.assertEqual(n_found[level], n_trixel_per_level[level],
751 msg=msg)
753 # make sure no trixels were duplicated
754 self.assertEqual(len(np.unique(list(trixel_dict.keys()))),
755 len(trixel_dict))
757 for htmid in trixel_dict.keys():
758 level = levelFromHtmid(htmid)
759 self.assertLessEqual(level, max_level)
760 self.assertGreaterEqual(level, 1)
761 t0 = trixelFromHtmid(htmid)
762 self.assertEqual(t0, trixel_dict[htmid])
764 def test_trixel_bounding_circle(self):
765 """
766 Verify that the trixel's bounding_circle method returns
767 a circle that contains all of the corners of the
768 trixel
769 """
770 rng = np.random.RandomState(142)
771 n_test_cases = 5
772 for i_test in range(n_test_cases):
773 htmid = (13 << 6)+rng.randint(1, 2**6-1)
774 trixel = trixelFromHtmid(htmid)
775 bounding_circle = trixel.bounding_circle
776 ra_0, dec_0 = sphericalFromCartesian(bounding_circle[0])
777 ra_list = []
778 dec_list = []
779 for cc in trixel.corners:
780 ra, dec = sphericalFromCartesian(cc)
781 ra_list.append(ra)
782 dec_list.append(dec)
783 ra_list = np.array(ra_list)
784 dec_list = np.array(dec_list)
785 distance = _angularSeparation(ra_0, dec_0,
786 ra_list, dec_list)
787 distance = arcsecFromRadians(distance)
788 radius = arcsecFromRadians(bounding_circle[2])
789 self.assertLessEqual(distance.max()-radius, 1.0e-8)
790 self.assertLess(np.abs(distance.max()-radius), 1.0e-8)
792 def test_trixel_contains_many(self):
793 """
794 Test that trixel.contains_pt and trixel.contains can
795 work with numpy arrays of input
796 """
797 htmid = (15 << 6) + 45
798 trixel = trixelFromHtmid(htmid)
799 ra_0, dec_0 = trixel.get_center()
800 radius = trixel.get_radius()
801 rng = np.random.RandomState(44)
802 n_pts = 100
803 rr = radius*rng.random_sample(n_pts)*1.1
804 theta = rng.random_sample(n_pts)*2.0*np.pi
805 ra_list = ra_0 + rr*np.cos(theta)
806 dec_list = dec_0 + rr*np.sin(theta)
807 contains_arr = trixel.contains(ra_list, dec_list)
808 n_in = 0
809 n_out = 0
810 for i_pt in range(n_pts):
811 single_contains = trixel.contains(ra_list[i_pt], dec_list[i_pt])
812 self.assertEqual(single_contains, contains_arr[i_pt])
813 if single_contains:
814 n_in += 1
815 else:
816 n_out += 1
818 self.assertGreater(n_in, 0)
819 self.assertGreater(n_out, 0)
821 xyz_list = cartesianFromSpherical(np.radians(ra_list),
822 np.radians(dec_list))
824 contains_xyz_arr = trixel.contains_pt(xyz_list)
825 np.testing.assert_array_equal(contains_xyz_arr, contains_arr)
828class MemoryTestClass(lsst.utils.tests.MemoryTestCase):
829 pass
832if __name__ == "__main__": 832 ↛ 833line 832 didn't jump to line 833, because the condition on line 832 was never true
833 lsst.utils.tests.init()
834 unittest.main()